Reference Type

B

baibaichen

Hi,

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
 
V

Victor Bazarov

baibaichen said:
Hi,

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?

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
 
B

baibaichen

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.

I tested typeid(str) == typeid(const std::string) and typeid(const
std::string&) == typeid(str), these two expression are both ture

-Chang
 
J

Juha Nieminen

baibaichen said:
Hi,

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?

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.
 
B

Balog Pal

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.
 
J

Juha Nieminen

Balog said:
The original types are different

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?
 
B

baibaichen

  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.

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
 
V

Victor Bazarov

Juha said:
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?

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".

V
 
A

Arne Mertz

baibaichen said:
Yes, you are right, As we know,

void foo(const std::string&);
void foo(const std::string);

are not permitted in C++,

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.
 
A

Andrey Tarasevich

baibaichen said:
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?

'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.
 
A

Andrey Tarasevich

Andrey said:
'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'.
 
A

Alf P. Steinbach

* Andrey Tarasevich:
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'.

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)
 
J

Juha Nieminen

Victor said:
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".

So is there any situation anywhere where you can distinguish between a
value and a const reference of the same type?
 
J

Juha Nieminen

Juha said:
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);
 
J

James Kanze

baibaichen wrote:
What do you mean by "the same 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.
 
J

James Kanze

baibaichen wrote:
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.

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.
 
H

Howard Hinnant

  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
 
A

Andrey Tarasevich

Juha said:
So is there any situation anywhere where you can distinguish between a
value and a const reference of the same type?

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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,070
Latest member
BiogenixGummies

Latest Threads

Top