2013-04-06 1 views
20

は、私は、これはGCCやクランで失敗し、私の驚きにこのコードコンパイラは "A(A&)"が右辺値を受け入れると考えていますか?

struct A { A(); A(A&); }; 
struct B { B(const A&); }; 

void f(A); 
void f(B); 

int main() { 
    f(A()); 
} 

を持っています。二fが正常に動作したときに、彼らは、最初のfを選択しないのはなぜ打ち鳴らすには、例えば

Compilation finished with errors: 
source.cpp:8:10: error: no matching constructor for initialization of 'A' 
     f(A()); 
     ^~~ 
source.cpp:1:21: note: candidate constructor not viable: expects an l-value for 1st argument 
    struct A { A(); A(A&); }; 
        ^
source.cpp:1:16: note: candidate constructor not viable: requires 0 arguments, but 1 was provided 
    struct A { A(); A(A&); }; 
      ^
source.cpp:4:13: note: passing argument to parameter here 
    void f(A); 

を言いますか?最初にfを削除すると、呼び出しは成功します。彼らはすべて二fを呼び出して、私はブレースの初期化、を使用している場合、それはまた、正常に動作します

int main() { 
    f({A()}); 
} 

、私にはもっと奇妙な何かです。

答えて

17

これは言語の癖です。 Aは引数タイプ(A)に一致する変換を必要としないため、最初のfがよりよく一致しますが、コンパイラが呼び出しを試みるときに適切なコピーコンストラクタが見つからないという事実により、呼び出しが失敗します。この言語では、過負荷解決のステップを実行する際の実際の呼び出しの実行可能性を考慮に入れることはできません。

最も近い標準引用ISO/IEC 14882:2011 13.3.3.1.2ユーザ定義変換配列[over.ics.user]:

同じクラスにクラス型の表現の変換型は完全一致ランクが与えられ、そのタイプの基本クラスに対するクラス型式の 変換は、 コピー/移動コンストラクタ(すなわち、ユーザ定義変換関数)が呼び出されます。リストの初期化ケースの場合

は、おそらく見てする必要があります。 13.3.3.1.2ユーザー定義の変換シーケンス[over.ics.user]

すると非集約クラスのオブジェクトタイプTリスト初期化(8.5.4)、オーバーロード解決は、2つのフェーズでコンストラクタ を選択している:

- まず、候補関数が初期化リストコンストラクタである(8.5.4)クラスTのと 引数リストはイニシャライザのリストで構成されていますル引数。

- ない生存初期化リストコンストラクタが見つからない場合、オーバーロード解決は、再び実行 候補関数は、クラスTのすべてのコンストラクタである場合、引数リストが初期化リストの要素 から構成されています。

オーバーロードの解決は、それがA(A&)A()をバインドしようとしているseqenceを拒否しなければならないf(A)f(B)のために、それぞれの場合の生contructorsを見て持っていますが、B(const A&)はまだ生きているので。

+0

ありがとうございます!私は '{...}'の場合にそのような規則を見つけることができません。それは '{...}'のケースがなぜ機能するのかを説明していますか? –

+0

@ JohannesSchaub-litb:わかりません、tbh、あなたは_braced-init-list_で関数を呼び出しているので、ルールはまったく異なります。 –

+0

@ JohannesSchaub-litb [over.ics.list]を参照してください。私はそれがover.icsと関係があると思う。(A&A)は、一時的ではない左辺値の参照にバインドするため、実行可能な関数のサブセットを形成するときに実行可能とはみなされません。 – dyp

関連する問題