[英]What is “Expression SFINAE”?
在http://blogs.msdn.com/b/vcblog/archive/2011/09/12/10209291.aspx上 ,VC ++團隊正式聲明他們尚未實現C ++ 11核心功能“ Expression SFINAE”。 但是,VC ++編譯器接受從http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2634.html復制的以下代碼示例。
范例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”?
我認為,您所鏈接的論文中對SFINAE的表達進行了很好的解釋。 在表達式上是SFINAE 。 如果decltype
的表達式無效,那么請從重載的VIP休息室中調用該函數。 您可以在此答案的末尾找到規范性措詞。
對VC的注意事項++:他們並沒有完全實現它。 在簡單的表達式上,它可能會起作用,但在其他表達式上,它將不起作用。 有關失敗的示例,請參見此答案的注釋中的討論。 為了簡單起見,這是行不通的:
#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);
}
對於Clang,這將輸出預期的結果:
可以致電參考
可以用指針呼叫
無法通話
使用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的常見用法是在定義特征時,例如用於檢查類是否具有某個成員函數的特征:
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)) {};
現場示例。 (令人驚訝的是,這再次適用於GCC 4.7.1。)
另請參閱我的答案,該答案在另一種環境(也稱為無特征)中使用相同的技術。
規范用語:
§14.8.2 [temp.deduct]
p6 在模板自變量推導過程中的某些點,必須采用利用模板參數的函數類型,並用相應的模板自變量替換這些模板參數。 當將任何顯式指定的模板參數替換為函數類型時,此操作在模板參數推論的開始時進行;當替換從默認參數推論或獲得的任何模板參數時,在模板參數推論的末尾再次進行 。
p7 替換發生在函數類型和模板參數聲明中使用的所有類型和表達式中。 表達式不僅包括常量表達式如那些出現在數組邊界或無類型模板參數而且 內部 一般表達式 (即,非常量表達式)
sizeof
,decltype
,和其它上下文允許非常量表達式。p8如果替換導致無效的類型或表達式,則類型推導失敗。 無效的類型或表達式是使用替換參數編寫的格式或表達式。 [...]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.