2012-09-29 13 views
50

http://blogs.msdn.com/b/vcblog/archive/2011/09/12/10209291.aspxでVC++チームは、C++ 11のコア機能「Expression SFINAE」をまだ実装していないことを正式に宣言しています。ただし、http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2634.htmlからコピーされた次のコード例は、VC++コンパイラによって受け入れられています。「表現SFINAE」とは何ですか?

例1:

template <int I> struct A {}; 

char xxx(int); 
char xxx(float); 

template <class T> A<sizeof(xxx((T)0))> f(T){} 

int main() 
{ 
    f(1); 
} 

例2:

struct X {}; 
struct Y 
{ 
    Y(X){} 
}; 

template <class T> auto f(T t1, T t2) -> decltype(t1 + t2); // #1 
X f(Y, Y); // #2 

X x1, x2; 
X x3 = f(x1, x2); // deduction fails on #1 (cannot add X+X), calls #2 

私の質問です: "式SFINAE" とは何ですか?

+0

なぜ明白に見ていない:http://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error – SChepurin

+5

@SChepurin:通常SFINAEを説明します式SFINAEではなく、しかし、それは良い点です。 OPは一般的にSFINAEについて知っていますか? – Xeo

+1

@Xeo、はい、私はSFINAEを一般的に知っています。あなたの説明のための多くのおかげです。 – xmllmx

答えて

62

表現SFINAEはあなたがリンクした論文でかなりうまく説明されていると思います。表現上はSFINAEです。 decltypeの式が有効でない場合は、VIPラウンジから過負荷の関数を取り除きます。この答えの最後に規範的な表現を見つけることができます。

VC++について:を実装していません。単純な表現ではうまくいくかもしれませんが、他の表現ではそうではありません。失敗した例については、on this answerのコメントを参照してください。それを簡単にするために、これは動作しません。

MSVCで

Could call with reference
Could call with pointer
Couldn't call

、私はよく...取得、コンパイルエラー:

クランで
#include <iostream> 

// catch-all case 
void test(...) 
{ 
    std::cout << "Couldn't call\n"; 
} 

// catch when C is a reference-to-class type and F is a member function pointer 
template<class C, class F> 
auto test(C c, F f) -> decltype((c.*f)(), void()) // 'C' is reference type 
{ 
    std::cout << "Could call on reference\n"; 
} 

// catch when C is a pointer-to-class type and F is a member function pointer 
template<class C, class F> 
auto test(C c, F f) -> decltype((c->*f)(), void()) // 'C' is pointer type 
{ 
    std::cout << "Could call on pointer\n"; 
} 

struct X{ 
    void f(){} 
}; 

int main(){ 
    X x; 
    test(x, &X::f); 
    test(&x, &X::f); 
    test(42, 1337); 
} 

が、これは予想を出力します

 
source.cpp: In substitution of 'template decltype ((c.*f(), void())) test(C, F) [with C = X*; F = void (X::*)()]': 
source.cpp:29:17: required from here 
source.cpp:11:6: error: cannot apply member pointer 'f' to 'c', which is of non-class type 'X*' 
source.cpp: In substitution of 'template decltype ((c.*f(), void())) test(C, F) [with C = int; F = int]': 
source.cpp:30:16: required from here 
source.cpp:11:6: error: 'f' cannot be used as a member pointer, since it is of type 'int' 
 
1>src\main.cpp(20): error C2995: ''unknown-type' test(C,F)' : function template has already been defined 
1>   src\main.cpp(11) : see declaration of 'test' 

はまた、GCC 4.7.1はかなりアップタスクにいないようですクラスは、特定のメンバ関数遊ばす場合

式SFINAEの一般的な使用が特色のような定義形質は、チェックするときです:

struct has_member_begin_test{ 
    template<class U> 
    static auto test(U* p) -> decltype(p->begin(), std::true_type()); 
    template<class> 
    static auto test(...) -> std::false_type; 
}; 

template<class T> 
struct has_member_begin 
    : decltype(has_member_begin_test::test<T>(0)) {}; 

Live example.(どちらが、意外にも、GCC 4.7.1で再び動作します。)

this answer of mineも参照してください。別の環境(別名なし)で同じ手法を使用しています。


規範の文言:

§14.8.2 [temp.deduct]

p6 At certain points in the template argument deduction process it is necessary to take a function type that makes use of template parameters and replace those template parameters with the corresponding template arguments. This is done at the beginning of template argument deduction when any explicitly specified template arguments are substituted into the function type, and again at the end of template argument deduction when any template arguments that were deduced or obtained from default arguments are substituted.

p7 The substitution occurs in all types and expressions that are used in the function type and in template parameter declarations. The expressions include not only constant expressions such as those that appear in array bounds or as nontype template arguments but also general expressions (i.e., non-constant expressions) insidesizeof , decltype, and other contexts that allow non-constant expressions.

p8 If a substitution results in an invalid type or expression, type deduction fails. An invalid type or expression is one that would be ill-formed if written using the substituted arguments. [...]

+0

私はliveworkspaceがgcc 4.7.2を使用していることに気づいたときに、なぜideoneの代わりにliveworkspaceへのリンクが突然現れたのだろうと思っていました。ああ!最後に! –

+2

実例のリンクが壊れています:( –

関連する問題