reference collapsing

C++98 では「参照への参照」は作ってはいけないことになっていました:

typedef int& ref_t;
ref_t& ref = 〜; // 駄目。参照の参照は無理。

これは、基本的には、思わぬミスを防げるので 良い仕様と言えるのですが、
テンプレートを使うときに、思わぬコンパイルエラーを引き起こします。
通常はテンプレートに何らかの参照を渡すことはないので、特に問題にはならないのですが、
もし参照も取り得るテンプレートで、コンパイルエラーを避けつつ参照を取得するには、
メタ関数を使って typename boost::add_reference::type などと書く必要がありました。


しかし、テンプレートが広く使われ、参照をテンプレートに渡すことも普通になってきた今では、
このようなメタプログラミングをする必要があるのは、初心者に厳しいですし、また単純に面倒です。
というわけで、 C++0x では部分的に「参照への参照」が作れるようになりました:

int& &ref = 〜; // 駄目。直接的に参照の参照を作ることは出来ない
typedef int& ref_t;
ref_t& ref = 〜; // この場合は大丈夫。

条件は、参照を付けられる型 TR が

  • typedefされた型
  • テンプレートパラメータ
  • decltype( 〜 )

である場合で、この場合には TR& や TR&& という表現はコンパイルエラーにならず、
適切な型に置き換えられることになります(これを reference collapsing と言います)。
その際のルールは「&& に対して & が優先される」というもので、
&& な型に && が付いたときのみ && で、それ以外は全て & になります。
詳しくは http://slashdot.jp/~eldesh/journal/476796 辺りを読んでみてください。


規格の文面はこちら( N3126 8.3.2 References [dcl.ref] )です:

5 There shall be no references to references, no arrays of references, and no pointers to references. The
  declaration of a reference shall contain an initializer (8.5.3) except when the declaration contains an explicit
  extern specifier (7.1.1), is a class member (9.2) declaration within a class definition, or is the declaration
  of a parameter or a return type (8.3.5); see 3.1. A reference shall be initialized to refer to a valid object
  or function. [ Note: in particular, a null reference cannot exist in a well-defined program, because the only
  way to create such a reference would be to bind it to the “object” obtained by dereferencing a null pointer,
  which causes undefined behavior. As described in 9.6, a reference cannot be bound directly to a bit-field.
  ―end note ]

6 If a typedef (7.1.3), a type template-parameter (14.3.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.
  [ Example:
  int i;
  typedef int& LRI;
  typedef int&& RRI;
  LRI& r1 = i; // r1 has the type int&
  const LRI& r2 = i; // r2 has the type int&
  const LRI&& r3 = i; // r3 has the type int&
  RRI& r4 = i; // r4 has the type int&
  RRI&& r5 = i; // r5 has the type int&&
  decltype(r2)& r6 = i; // r6 has the type int&
  decltype(r2)&& r7 = i; // r7 has the type int&
  ―end example ]