読者です 読者をやめる 読者になる 読者になる

altebute.hatenablog.com

犬も歩けば規格にあたる

参照型に対するcv修飾子はill-formedまたは無視される

const int&const int への参照であるため、well-formedであるが、 int& constint&に対するcv修飾であるためill-formedである。
ただし、cv修飾される型名が typedef-name または decltype-specifier の場合、cv修飾子は無視される。
また、同時に reference collapsing が起きる場合も、cv修飾子は同様に無視される。

このため、明示的にcv修飾を行った場合も、予想しない型になる場合がある。

#include <type_traits>
#include <iostream>
#include <boost/type_index.hpp>

using namespace std;
using boost::typeindex::type_id_with_cvr; 

template< typename Arg > void f()
{
    cout << "================================" << endl;
    cout << "`Arg`         is `" << type_id_with_cvr< Arg         >() << "`." << endl;
    cout << "`Arg&`        is `" << type_id_with_cvr< Arg&        >() << "`." << endl;
    cout << "`Arg&&`       is `" << type_id_with_cvr< Arg&&       >() << "`." << endl;
    cout << "--------------------------------" << endl;
    cout << "`Arg const`   is `" << type_id_with_cvr< Arg const   >() << "`." << endl;
    cout << "`Arg const&`  is `" << type_id_with_cvr< Arg const&  >() << "`." << endl;
    cout << "`Arg const&&` is `" << type_id_with_cvr< Arg const&& >() << "`." << endl;
}

int main()
{
    f< int         >();
    f< int&        >();
    f< int&&       >();
    f< const int   >();
    f< const int&  >();
    f< const int&& >();
    cout << "================================" << endl;
    cout << "voltile work same as const." << endl;
}

出力

> Start
================================
`Arg`         is `int`.
`Arg&`        is `int&`.
`Arg&&`       is `int&&`.
--------------------------------
`Arg const`   is `int const`.
`Arg const&`  is `int const&`.
`Arg const&&` is `int const&&`.
================================
`Arg`         is `int&`.
`Arg&`        is `int&`.
`Arg&&`       is `int&`.
--------------------------------
`Arg const`   is `int&`.
`Arg const&`  is `int&`.
`Arg const&&` is `int&`.
================================
`Arg`         is `int&&`.
`Arg&`        is `int&`.
`Arg&&`       is `int&&`.
--------------------------------
`Arg const`   is `int&&`.
`Arg const&`  is `int&`.
`Arg const&&` is `int&&`.
================================
`Arg`         is `int const`.
`Arg&`        is `int const&`.
`Arg&&`       is `int const&&`.
--------------------------------
`Arg const`   is `int const`.
`Arg const&`  is `int const&`.
`Arg const&&` is `int const&&`.
================================
`Arg`         is `int const&`.
`Arg&`        is `int const&`.
`Arg&&`       is `int const&`.
--------------------------------
`Arg const`   is `int const&`.
`Arg const&`  is `int const&`.
`Arg const&&` is `int const&`.
================================
`Arg`         is `int const&&`.
`Arg&`        is `int const&`.
`Arg&&`       is `int const&&`.
--------------------------------
`Arg const`   is `int const&&`.
`Arg const&`  is `int const&`.
`Arg const&&` is `int const&&`.
================================
voltile work same as const.
0
Finish

以下は N3797 項 8.3.2 より引用。

1
In a declaration T D where D has either of the forms & attribute-specifier-seqoptD1 && attribute-specifier-seqoptD1 and the type of the identifier in the declaration T D1 is “derived-declarator-type-list T,” then the type of the identifier of D is “derived-declarator-type-list reference to T.” The optional attribute-specifier-seq appertains to the reference type. 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-specificer (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 ] [ Note: A reference can be thought of as a name of an object. ? end note ] A declarator that specifies the type “reference to cv void” is ill-formed.

6
If a typedef-name (7.1.3, 14.1) or a decltype-specifier (7.1.6.2) denotes a type TR that is a reference to a type T, an attempt to create the type “lvalue reference to cv TR” creates the type “lvalue reference to T”, while an attempt to create the type “rvalue reference to cv TR” creates the type TR.