2017-09-05 12 views
13

のC++ 17のパラメータ控除テンプレートの原因の曖昧さをコンストラクタができます。私は、テンプレート関数(ここではコンストラクタ)が過負荷解決の優先順位を低くしていると考えました。ここには当てはまりませんか?は、簡単な例を考えてみましょクラステンプレート

エラーメッセージ:

prog.cc:10:14: error: ambiguous deduction for template arguments of 'foo' 
    foo  f1(foo<int>{}); //case 1. 
      ^
prog.cc:4:5: note: candidate function [with T = int, TT = foo] 
    foo(TT<T>&&) {} 
    ^
prog.cc:5:5: note: candidate function [with T = int] 
    foo(foo<T>&&){} 
    ^
1 error generated. 

[clang demo][gcc demo]

答えて

11

これはClangのバグです。候補セットが形成された後、暗黙の変換シーケンスおよびテンプレート関数の順序付けを行うための同じルールを使用して最良の過負荷が選択されるので、候補セットがc'torsから形成されるという事実は重要ではない。

[over.match.funcs]/1引用すると:[over.match.funcs]の

副次句を候補 関数のセットと の解像度をオーバーロードするために提出した引数リスト7つの各コンテキストを記述している過負荷で解像度が使用されます。 で定義されているソース変換と構造は、オーバーロードの解決方法 の処理を説明するためのものです。実装は、そのような変換 と構造を使用する必要はありません。

これは、過負荷解決プロセスが常に同じであることを明確に示しています。唯一の違いは候補セットがどのように形成されるかです。

そして[over.match.class.deduct]/1

によって指定された関数と関数テンプレートのセットが形成されている前記テンプレート名で指定されたプライマリクラステンプレートの各コンストラクタの

  • 、もしテンプレートが定義されている場合、 の関数テンプレートは次のプロパティを持ちます。

    • テンプレートパラメータは、クラステンプレートのテンプレートパラメータと、それに続くコンストラクタのテンプレートパラメータ(デフォルトの テンプレート引数を含む)です(存在する場合)。

    • 関数パラメータの型はコンストラクタの型です。

    • 戻り値の型は、クラステンプレートから取得されたテンプレート のパラメータに対応するテンプレート名とテンプレート引数によって指定されるクラステンプレートの特殊化です。

各c'torは、候補セットに擬似関数を導入します。このように:これが無料の機能がbarた場合

template <class T>       foo(foo<T>&&) -> foo<T> 
template <class T, template<class> class TT> foo(TT<T>&&) -> foo<T> 

は、さらに説明するために:

template <template <class> class TT, class T> 
void bar(TT<T>&&) {} 

template <class T> 
void bar(foo<T>&&){} 

そして、テンプレート関数の順序が第二より低い最初の過負荷を置きます。

+0

あなたは正しいかもしれませんが、私は標準的な参考文献に満足しています。 MSVCもこれを爆破する。編集:あなたは私にそれを打つ。ありがとうございました。 – AndyG

+1

コピー控除候補はどうですか? –

+0

@VaughnCato - それはリストの次の弾です。しかし、私はそれがあいまいであるべきかどうかには関係しないと思う。 – StoryTeller

1

彼らは低い優先順位を持っていません。 SFINEAを使用して問題を解決できます。これはScott MeyersのEffective Modern C++に記述されています。

template <class T> 
struct foo { 
    template <template <class> class TT, class = std::enable_if_t<!std::is_same_v<foo<T>, std::decay_t<TT<T>>>>> 
    foo(TT<T>&&) {} 
    foo(foo<T>&&){} 
    foo() {} 
}; 
+0

を参照してください。これがフリー関数呼び出しであれば、順序ルールは非常に明確です。 – StoryTeller

+0

私は答えへの参照を追加しました –

+3

いいえ、私は標準的な参照のように意味しました。私はMyersの本を読んでいて、これはそれでカバーされていません。あなたはここでさまざまなことを融合させています。 – StoryTeller

関連する問題