Substitution failure is not an error

44 篇文章 6 订阅

Substitution failure is not an error

From Wikipedia, the free encyclopedia

Substitution failure is not an error (SFINAE) refers to a situation in C++ where an invalid substitution of templateparameters is not in itself an error. David Vandevoorde first introduced the acronym SFINAE to describe related programming techniques.[1]

Specifically, when creating a candidate set for overload resolution, some (or all) candidates of that set may be the result of instantiated templates with (potentially deduced) template arguments substituted for the corresponding template parameters. If an error occurs during the substitution of a set of arguments for any given template, the compiler removes the potential overload from the candidate set instead of stopping with a compilation error, provided the substitution error is one the C++ standard grants such treatment.[2] If one or more candidates remain and overload resolution succeeds, the invocation is well-formed.

Example

The following example illustrates a basic instance of SFINAE:

struct Test {
    typedef int foo;
};
 
template <typename T> 
void f(typename T::foo) {} // Definition #1
 
template <typename T> 
void f(T) {}                // Definition #2
 
int main() {
    f<Test>(10); // Call #1.
    f<int>(10);  // Call #2. Without error (even though there is no int::foo) thanks to SFINAE.
}

Here, attempting to use a non-class type in a qualified name (T::foo) results in a deduction failure for f<int> because int has no nested type named foo, but the program is well-formed because a valid function remains in the set of candidate functions.

Although SFINAE was introduced to avoid creating ill-formed programs when unrelated template declarations were visible (e.g., through the inclusion of a header file), many developers found the behavior useful for compile-time introspection. Specifically, it allows a template to determine certain properties of its template arguments at instantiation time.

For example, SFINAE can be used to determine if a type contains a certain typedef:

#include <iostream>
 
template <typename T>
struct has_typedef_foobar {
    // Types "yes" and "no" are guaranteed to have different sizes,
    // specifically sizeof(yes) == 1 and sizeof(no) == 2.
    typedef char yes[1];
    typedef char no[2];
 
    template <typename C>
    static yes& test(typename C::foobar*);
 
    template <typename>
    static no& test(...);
 
    // If the "sizeof" of the result of calling test<T>(0) would be equal to sizeof(yes),
    // the first overload worked and T has a nested type named foobar.
    static const bool value = sizeof(test<T>(0)) == sizeof(yes);
};
 
struct foo {    
    typedef float foobar;
};
 
int main() {
    std::cout << std::boolalpha;
    std::cout << has_typedef_foobar<int>::value << std::endl;
    std::cout << has_typedef_foobar<foo>::value << std::endl;
}

When T has the nested type foobar defined, the instantiation of the first test works and 0 is successfully passed as the null pointer constant. (And the resulting type of the expression is yes.) If it does not work, the only available function is the secondtest, and the resulting type of the expression is no. (An ellipsis is used not only because it will accept any argument, but also because its conversion rank is lowest, so a call to the first function will be preferred if it is possible; this removes ambiguity.)

Developers of Boost used SFINAE in boost::enable_if[3] and in other ways.

References

  1. Vandevoorde, David; Nicolai M. Josuttis (2002). C++ Templates: The Complete Guide. Addison-Wesley Professional. ISBN 0-201-73484-2.
  2. International Organization for Standardization. "ISO/IEC 14882:2003, Programming languages — C++", § 14.8.2.
  3. Boost Enable If

Categories:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值