2012-09-29 37 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中的表達式無效,那麼請從貴賓休息室啓動超載功能。你可以在這個答案的最後找到規範的措詞。

關於VC++的說明:他們沒有實現它完全。在簡單的表達式上,它可能有效,但在其他情況下,它不會。請參閱on this answer評論中有關失敗示例的討論。爲簡單起見,這是不行的:

#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); 
} 

鏗鏘,這種輸出的預期:

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

隨着MSVC,我得到......嗯,一個編譯器錯誤:

 
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是沒有達到的任務:

 
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' 

一個常見用途表達的SFINAE是定義特質的時候,就像一個特徵來檢查類體育某個成員函數:(其中,奇怪的是,再次GCC 4.7.1工程)

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.

另請參閱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而不是ideone的鏈接,當我注意到liveworkspace正在使用gcc 4.7.2。啊!最後! –

+2

生活示例鏈接損壞:( –