I test the following codes in VC++ and GCC
const std::string& str = "";
std::cout << typeid(str).name() << std::endl;
std::cout << typeid(const std::string&).name()<< std::endl;
std::cout << typeid(const std::string).name()<< std::endl;
Both think str, const std::string& and const std::string are the same
type!
Aren't str and const std::string& reference type?
thanks
Chang
What do you mean by "the same type"?
> Aren't str and const std::string& reference type?
They are. Have you tried comparing 'typeid(str)' with 'typeid(const
std::string)'? Does it compare equal or not?
Using 'name' of the std::type_info is not guaranteed to give any
meaningful results (although some compilers are known to produce some
kind of humanly readable strings), so compare objects, not their names.
V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
I tested typeid(str) == typeid(const std::string) and typeid(const
std::string&) == typeid(str), these two expression are both ture
-Chang
There's no such a thing as a "reference type" (as opposed to other
types). A reference is simply an "alias" to something, and it behaves
exactly like that something. Its type is that of that something.
>I tested typeid(str) == typeid(const std::string) and typeid(const
std::string&) == typeid(str), these two expression are both ture
That is hod typeid() works... It strips 'reference' and the top level const.
The original types are different, but map to the same typeid.
Are you sure? How do you differentiate between them anywhere?
For example, if you have an overloaded function:
void foo(int);
void foo(const int&);
How do you call this function?
Yes, you are right, As we know,
void foo(const std::string&);
void foo(const std::string);
are not permitted in C++, it is also an evidence of "reference isn't
type, but
void foo(const std::string&);
...
std::cout<< typeid(foo).name << std:endl;
In this case, VC would clearly tell us that the parameter is a
*reference type*(Gcc also report the same result with unfriendly
words).
Chang
You don't. A call 'foo(42)' would be ambiguous because reference
binding is an identity conversion and has the same rank as "no conversion".
Why shouldn't it be permitted? It's only not easy to use because you
can't call the functions directly because the call would be
ambigous. If the parameters were not const, you could call the
second one directly by providing an const parameter, because then
(and only then) the compiler could figure out that the first
function was not applicable because a const object cannot be bound
to a const reference. However, you _can_ call both functions through
function pointers, because the functions' types are different and
therefore you can assign the function's adresses to appropiate fptrs:
void foo(const std::string&) {cout << "ref version!" << endl; }
void foo(const std::string) { cout << "str version!" << endl ;}
int main()
{
void (*pfr)(std::string const&) = &foo;
void (*pfs)(std::string const) = &foo;
pfr(""); //ref version!
pfs(""); //str version!
}
>
> void foo(const std::string&);
> ...
> std::cout<< typeid(foo).name << std:endl;
>
> In this case, VC would clearly tell us that the parameter is a
> *reference type*(Gcc also report the same result with unfriendly
> words).
Yes it does, because a function taking a reference has another type
than an function taking an object.
In the C++ standard, a reference to T indeed is another type than T
itself.
BUT the standard explicitly states (5.2.8) that typeid() yields an
type_info representing the referenced type if passed a type-id that
is a reference type. Equally, toplevel cv-qualifiers are ignored, so
typeid(T) == typeid(T const) == typeid(T&) == typeid(T const&).
Summary: T& and T are different types, but typeid yields the same
type_info object.
'const std::string&' is a reference type. As for 'str', it gets more
complicated. 'str' _itself_ is a reference, no argument about it.
However, 'str' as an C++ _expression_ has type 'const std::string'. No
reference in it.
The point his that 'typeid' in C++ works with the type of the
_expression_ supplied as an argument. Now, in C++ expressions never
really have reference type, in a sense that whenever you have an
expression that is supposed to evaluate to a value of type 'T&', the
resultant type is immediately adjusted to 'T' (as an lvalue, see 5/6).
I.e. when it comes to expression results, reference type is very
short-lived, it decays from 'T&' to 'T' so quickly, that you never
really get a chance to see that 'T&'. That is exactly what happens in
your code.
Additionally, 'typeid' can accept a type specifier as an argument, in
which case the language specification explicitly requires that the
result for type 'T&' is the same as for type 'T'.
--
Best regards,
Andrey Tarasevich
From a philosophical point of view one might say that C++ references are like
quantum wavefunctions.
Logic dictates that they're there, and it's no big deal to create one, or copy one.
However, try to get hold of one in the "raw" state and it's a slippery beast indeed.
- Alf (philosophical, liked your explanation)
--
Due to hosting requirements I need visits to <url: http://alfps.izfree.com/>.
No ads, and there is some C++ stuff! :-) Just going there is good. Linking
to it is even better! Thanks in advance!
So is there any situation anywhere where you can distinguish between a
value and a const reference of the same type?
Ah, there is:
(static_cast<void(*)(const int&)>(foo))(42);
> > I test the following codes in VC++ and GCC
> > const std::string& str = "";
> > std::cout << typeid(str).name() << std::endl;
> > std::cout << typeid(const std::string&).name()<< std::endl;
> > std::cout << typeid(const std::string).name()<< std::endl;
> > Both think str, const std::string& and const std::string are
> > the same type!
> What do you mean by "the same type"?
> > Aren't str and const std::string& reference type?
> They are. Have you tried comparing 'typeid(str)' with
> 'typeid(const std::string)'? Does it compare equal or not?
They should. Typeid ignores the top level const, and returns
the referenced type for references.
> Using 'name' of the std::type_info is not guaranteed to give
> any meaningful results (although some compilers are known to
> produce some kind of humanly readable strings), so compare
> objects, not their names.
It shouldn't make any difference in this case.
--
James Kanze (GABI Software) email:james...@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
> Are you sure? How do you differentiate between them anywhere?
You don't. At least not with typeid.
> For example, if you have an overloaded function:
> void foo(int);
> void foo(const int&);
> How do you call this function?
Any call would be ambiguous, I think. At any rate, I don't see
what this has to do with typeid.
The standard speaks of reference types. I think what you're
trying to get at is that references aren't objects; they are
simply aliases for other objects.
That is, at least, how the stanard presents it. On the other
hand, in the preable to expression (section 5, paragraph 6), it
says that "if an expression initially has the type `reference to
T', the type is adjusted to `T' prior to any further analysis."
Except, of course, that an expression which initially has a
reference type is always an lvalue.
In sum: references are types, but they aren't types, depending.
> So is there any situation anywhere where you can distinguish between a
> value and a const reference of the same type?
#include <iostream>
#include <boost/type_traits.hpp>
template <class T> struct get_name;
template <>
struct get_name<int>
{
std::string operator()() const {return "int";}
};
template <>
struct get_name<char>
{
std::string operator()() const {return "char";}
};
template <class T>
void
display()
{
using namespace boost;
typedef typename remove_reference<T>::type Tr;
typedef typename remove_cv<Tr>::type Trcv;
if (is_const<Tr>::value)
std::cout << "const ";
if (is_volatile<Tr>::value)
std::cout << "volatile ";
std::cout << get_name<Trcv>()();
if (is_reference<T>::value)
std::cout << '&';
std::cout << '\n';
}
int main()
{
display<int>();
display<int&>();
display<const int&>();
display<char>();
display<char&>();
display<const char&>();
}
Outputs for me:
int
int&
const int&
char
char&
const char&
The display function above can be refined/extended to portably print
out a good description of any type.
If it helps, here is a diagram of C++ types and how they are
classified (those types you may not recognize are introduced in C+
+0X):
http://home.roadrunner.com/~hinnant/TypeHiearchy.pdf
The <boost/type_traits.hpp> used above will be <type_traits> in
namespace std for C++0X (well, very similar, not exactly the same).
-Howard
Specifically in a _value_ context? No, if I'm not missing anything.
In a type context, it is possible to distinguish a reference type from
non-reference type (template partial specialization does that), but not
in a value context.
> In sum: references are types, but they aren't types, depending.
>
They are types. But in some contexts they are treated different.
greets
Arne
>
> From a philosophical point of view one might say that C++ references
> are like
> quantum wavefunctions.
>
> Logic dictates that they're there, and it's no big deal to create one,
> or copy one.
>
> However, try to get hold of one in the "raw" state and it's a slippery
> beast indeed.
Quantum wavefunctions can collapse into different states randomly; I
sincerely hope this is not the case with C++ references :-)
Paavo
> From a philosophical point of view one might say that C++ references are like
> quantum wavefunctions.
>
> Logic dictates that they're there, and it's no big deal to create one, or copy one.
>
> However, try to get hold of one in the "raw" state and it's a slippery beast indeed.
>
So... we know that code often exhibits "Heisenbugs", which go away
when you look at them.
Does your analogy mean that Schroedinger's Code exhibits undefined
behavior until we look
at it?
Schroedinger's Code was collapsed via a single click in the left margin in
Visual Studio's Live Code editor.
Since then nobody's bothered to look at it, and it may or may not have been
migrated to the Dead Code repository, or a little of both.
And yes, that's probably the source of all this weird behavior...
Cheers,
- Alf
Er... My code's name is Mittens.