C++11ではクラスのメンバ関数をref-qualifier修飾できる。
メンバ関数に対するref-qualifierは、メンバ関数の暗黙のパラメタ(*thisに対応する)に対するref-qualifierとなる。
ただし、メンバ関数がref-qualifier修飾されていない場合、暗黙のパラメタはlvalue-reference修飾される。(N3337 13.3.1 第4段落)
struct foo
{
void f() &; //1
void f() &&; //2
};
foo a;
a.f(); //1が呼ばれる
foo().f(); //2が呼ばれる
この機能はmoveセマンティクスをより多くのシーンで使うために導入された。
ところで、この規格の元でC++11のオーバーロード解決の仕組みを用いると、既存のコードが動かなくなる。
なぜなら、lvalue-referenceはrvalueを束縛できないからだ。
すなわち
struct foo
{
void f() &;
};
foo().f(); //rvalueはlvalue-referenceで束縛できない
struct hoge
{
void f() const&;
};
hoge().f(); //const-lvalue-referenceならばできる。
この規格の変更はあまりにも多くの既存のコードを破壊するので、次の例外が追加された。
ref-qualifier修飾されていないメンバ関数のオーバーロード解決においてのみ、const修飾されていなくても、rvalueを暗黙のlvalue-referenceパラメタに束縛できる。(N3337 13.3.1 第5段落)
struct foo
{
void f() &;
};
foo().f() ; //今やちゃんとfoo::fが呼ばれる。
ところで、アルティメットメタプログラマー諸兄ならば、&と&&が違うだけの似たようなコードを2つ書くよりも、メタプログラミングによるスリム化を好むだろう。
ところが、恐らくそれはできない。
なぜならば、呼び出し元のクラスオブジェクトについての情報はthisを通しとのみ入ってくるが、*thisは常にlvalueである。従って、decltypeを使って、ref-qualifierを引っ張りだす事はできない。
悲しい。
もし、ref-qualifier修飾されていないメンバ関数内で呼び出し元のクラスオブジェクトの型を取得する方法を知っている人がいたら教えてほしい。
追記:なぜか括弧が消えていたので直した。