1 回答
TA贡献1828条经验 获得超3个赞
我认为,您所链接的论文中对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):错误C2995:“未知类型” test(C,F)':功能模板已经定义
1> src \ main.cpp(11):参见'test'的声明
似乎GCC 4.7.1还不能完全完成任务:
source.cpp:代替'模板decltype((c。* f(),void()))test(C,F)[C = X *; F =无效(X :: *)()]':
source.cpp:29:17:从这里需要
source.cpp:11:6:错误:无法将成员指针'f'应用于非类类型'X *'的'c'
source.cpp:代替'template decltype((c。* f(),void()))test(C,F)[C = int; F = int]':
source.cpp:30:16:从这里需要
source.cpp:11:6:错误:'f'不能用作成员指针,因为它的类型为'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 替换发生在函数类型和模板参数声明中使用的所有类型和表达式中。表达式不仅包括常量表达式(例如出现在数组范围内或作为非类型模板参数的常量表达式),而且还包括,和内部 允许非常量表达式的其他通用表达式(即,非常量表达式)。sizeofdecltype
p8如果替换导致无效的类型或表达式,则类型推导失败。无效的类型或表达式是使用替换参数编写的格式或表达式。[...]
- 1 回答
- 0 关注
- 426 浏览
添加回答
举报