23

C ++ 0xでは、SFINAEルールが簡略化され、演繹の「即時コンテキスト」で発生する無効な式または型がコンパイラエラーではなく、演繹失敗(SFINAE)になります。

私の質問はこれです:
私がオーバーロードされた関数のアドレスを取り、それを解決できない場合、その失敗は演繹の直接の文脈でですか?
(つまり、ハードエラーですか、それとも解決できない場合はSFINAEですか)?

サンプルコードは次のとおりです。

struct X
{
  // template<class T> T* foo(T,T); // lets not over-complicate things for now
  void foo(char);
  void foo(int);
};


template<class U> struct S
{
  template<int> struct size_map 
  { typedef int type; };


// here is where we take the address of a possibly overloaded function
  template<class T> void f(T, 
      typename size_map<sizeof(&U::foo)>::type* = 0); 


  void f(...);
};

int main()
{
  S<X> s;

// should this cause a compiler error because 'auto T = &X::foo' is invalid?
  s.f(3);  

}

Gcc 4.5は、これがコンパイラエラーであると述べており、clangはアサーション違反を吐き出します。

関心のあるいくつかの関連する質問があります:

FCD-C ++ 0xは、ここで何が起こるべきかを明確に指定していますか?
コンパイラはこのコードを拒否するのは間違っていますか?
演繹の「即時コンテキスト」をもう少し適切に定義する必要がありますか?

ありがとう!

4

1 に答える 1

29
template<class T> void f(T, 
    typename size_map<sizeof(&U::foo)>::type* = 0); 

U演繹に参加しないため、これは機能しません。Uは依存型ですが、控除中はf非依存型の名前で綴られた固定型のように扱われます。のパラメータリストに追加する必要がありますf

/* fortunately, default arguments are allowed for 
 * function templates by C++0x */
template<class T, class U1 = U> void f(T, 
    typename size_map<sizeof(&U1::foo)>::type* = 0); 

したがって、あなたの場合、それ自体U::fooのパラメータに依存しないためf、暗黙的にインスタンス化するときにエラーが発生しますS<X>(呼び出しをコメントアウトしてみてください。それでも失敗するはずです)。FCDはで言います14.7.1/1

クラステンプレート特殊化の暗黙的なインスタンス化により、クラスメンバー関数、メンバークラス、静的データメンバー、およびメンバーテンプレートの宣言の暗黙的なインスタンス化が発生しますが、定義やデフォルトの引数のインスタンス化は発生しません。

つまり、暗黙的にインスタンス化S<X>すると、次の関数テンプレート宣言がインスタンス化されます

template<class T> void S<X>::f(T, 
  typename size_map<sizeof(&X::foo)>::type* = 0); 

X::fooそのテンプレート宣言を分析すると、への参照を解決できず、エラーが発生することがわかります。を追加すると、テンプレート宣言は(のパラメータであるため)U1への参照をまだ解決しようとしないため、が呼び出されようとすると有効であり、SFINAEのままになります。U1::fooU1ff

于 2010-05-23T14:38:08.283 に答える