Home > Enterprise >  Binding const reference to another type
Binding const reference to another type

Time:10-10

How to know if you can bind a const reference T1 to T2 ?

I used to think that you can bind const reference T1 to type T2 only if T2 is convertible to T1. But since the following compiles:

char x[10];
const char (&y)[10] = x;

that should not be the case, since char[10] is not convertible to const char[10] (correct me if I'm wrong). So, what are the rules for being able to bind const references to different types ? Is there just an additional rule like: for any type T you can bind a const reference T to it ?

CodePudding user response:

The standard describes the reference binding rules in [dcl.init.ref]/4 and [dcl.init.ref]/5. There is a rather long list of rules, but the bits most relevant to your question are:

[dcl.init.ref]/4:

Given types “cv1 T1” and “cv2 T2”, “cv1 T1” is reference-related to “cv2 T2” if T1 is similar ([conv.qual]) to T2, or T1 is a base class of T2. “cv1 T1” is reference-compatible with “cv2 T2” if a prvalue of type “pointer to cv2 T2” can be converted to the type “pointer to cv1 T1” via a standard conversion sequence ([conv]).

[dcl.init.ref]/5:

A reference to type “cv1 T1” is initialized by an expression of type “cv2 T2” as follows:

— If the reference is an lvalue reference and the initializer expression
    — is an lvalue (but is not a bit-field), and “cv1 T1” is reference-compatible with “cv2 T2”, or
    [...]
then the reference binds to the initializer expression lvalue [...]

In your case, T1 would be const char [10] and T2 would be char [10]. T1 is reference-compatible with T2 because T2* can be converted to T1*, as it only requires adding const-qualification to the pointed type, which is a standard conversion.

As you can see in the referenced sections, this is not the only case where reference binding is allowed - another case, for example, is binding a reference to a result of conversion (including user-defined). const references are also special as they are allowed to bind to rvalues.

Note that this is indeed different from your previous understanding - T2 may not be convertible to T1 while you may be able to bind a reference still. Here's an example:

struct A
{
    A(int);
    A(A const&) = delete;
};

struct B : A
{
    B() : A(10) {}
};

B b;
A& ra = b; // ok, binds to base subobject A of b
A a = b;   // fail, A cannot be constructed from an object of B
  • Related