Search code examples
c++templatesperfect-forwardingtype-deduction

Why const is ignored when deducing type from universal reference?


Here is the definition of my A class and make function for it:

template< typename T >
class A
{
public:
    A( T test )
    : _test( test )
    {}

public:
    const T _test;
};

template <typename T>
A<T> make_a (T&& elem) {
    return A<T>{std::forward<T>(elem)};
}

When I pass int lvalue to make_a function, I expect the instantiated class to be similar to

class B
{
public:
    B( int &test )
    : _test( test )
    {}

public:
    const int &_test;
};

But the type of A::_test is deduced to be int& instead of const int&:

int main(int argc, const char * argv[]) {

    int a = 1;
    auto aa = make_a(a);
    aa._test = 2; // compiled OK

    B bb(a);
    bb._test = 2; // compilation error
    return 0;
}

Can anybody explain me what causes such behaviour?

I'm using XCode 7.0, LLVM 7.0 default compiler.

Thanks.


Solution

  • This behaviour is caused by the language standard.

    N4140 §8.3.2 [dcl.ref]/1

    Cv-qualified references are ill-formed except when the cv-qualifiers are introduced through the use of a typedef-name (7.1.3, 14.1) or decltype-specifier (7.1.6.2), in which case the cv-qualifiers are ignored. [ Example:

    typedef int& A;
    const A aref = 3; // ill-formed; lvalue reference to non-const initialized with rvalue
    

    The type of aref is “lvalue reference to int”, not “lvalue reference to const int”. —end example ]