理解SFINAE

14
据我所知,SFINAE意味着替换失败不会导致编译错误,而只是从可能的重载列表中删除原型。但我不明白为什么这是SFINAE。
template <bool C, typename T = void> struct enable_if{};
template <typename T> struct enable_if<true, T> { typedef T type; };

但这并不是什么吗?
template <bool C> struct assert;
template <> struct assert<true>{};

据我理解,这里的基本逻辑是相同的。这个问题来自于对这个答案的评论。


5
两个代码都不符合SFINAE(副作用不影响函数类型推断)。 - jrok
2
你似乎回答了自己的问题:SFINAE(替换失败不会导致编译时错误)不会导致编译时错误,而静态断言的整个目的是在某些条件不成立时导致编译时错误。 - gx_
1
@jrok 维基百科说 enable_if 是 SFINAE,这是错误的吗? - nikolas
4
enable_if 模板是在其他上下文中触发 SFINAE 的已经确立的方式。但它本身只是一个类模板。 - jrok
1
很有趣的是,看到术语辩论的评论得到了回复和赞,而我的评论似乎完全被忽视了... :') - gx_
显示剩余4条评论
1个回答

18
在C++98中,SFINAE是通过返回类型或带有默认参数的函数虚拟参数来完成的。
// SFINAE on return type for functions with fixed arguments (e.g. operator overloading)
template<class T>
typename std::enable_if< std::is_integral<T>::value, void>::type
my_function(T const&);

// SFINAE on dummy argument with default parameter for functions with no return type (e.g. constructors)
template<class T>
void my_function(T const&, std::enable_if< std::is_integral<T>::value, void>::type* = nullptr);

在这两种情况下,将T替换为嵌套类型type是SFINAE的本质。与std::enable_if相比,您的assert模板没有可用于SFINAE替换部分的嵌套类型
有关更多详细信息以及C++11表达式SFINAE,请参见Jonathan Wakely的ACCU 2013演示文稿。正如评论中@BartekBanachewicz指出的那样,现在还可以在函数模板默认参数中使用SFINAE。
// use C++11 default function arguments, no clutter in function's signature!
template<class T, class dummy = typename std::enable_if< std::is_integral<T>::value, void>::type>
void my_function(T const&);

3
“enable_if”不是SFINAE,但“typename enable_if<C>::type”是SFINAE,因为如果模板替换失败(只要它不是唯一的匹配项),它将不会导致错误。请注意,这里的“不是SFINAE”是指不是用于SFINAE的完整表达式形式。 - nikolas
@dyp:不,C++98 中有默认模板参数。否则你就不能使用 std::set<int> 作为 std::set<int, std::less<int>, std::allocator<int>> 的简写了。 - aschepler
@aschepler C++11为函数模板添加了默认模板参数,您的示例是关于C++98中已经存在的类模板 - TemplateRex
1
是的,我明白。但是在C++98中仍然可以使用默认模板参数来利用SFINAE。 - aschepler
@aschepler 当然,我应该在我的评论中提到函数模板。 我想要表达的是,第一个代码块中的第二个版本在C++98/03中是不合法的,但现在已经得到了修复。(删除评论..) - dyp
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接