SFINE

本文深入解析SFINAE(Substitution Failure is Not an Error)规则,阐述其在C++模板元编程中的作用,以及参数替换的具体时间和场景。文章还列举了多种SFINAE应用实例,包括类型检查、条件编译等,帮助读者全面理解SFINAE的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.何为sfine

Substitiution Faliure is Not an Error.这项规则被应用于函数模板重载决议时。当替换模板具体参数或演绎参数失败时,该具现化被从当前重载集中抛弃而不是让编译器报错。这个特性也被应用于模板元编程中。

2.参数替换发生时间

模板参数(template parameters)被模板变量(template arguments)代替两次:

  • explicitly specified template arguments are substituted before template argument deduction
  • deduced arguments and the arguments obtained from the defaults are substituted after template argument deduction

什么地方会发生变量替换呢

  • All type used in function type
  • all types used in the template parameter declarations
  • all expressions used in the function type
  • all expressions used in a template parameter declaration
  • all expressions used in the explicit specifier

sfine何时发生

  • A substitution failure is any situation when the type or expression above would be ill-formed (with a required diagnostic), if written using the substituted arguments.
  • Only the failures in the types and expressions in the immediate context of the function type or its template parameter types or its explicit specifier (since C++20) are SFINAE errors. If the evaluation of a substituted type/expression causes a side-effect such as instantiation of some template specialization, generation of an implicitly-defined member function, etc, errors in those side-effects are treated as hard errors. A lambda expression is not considered part of the immediate context. (since C++20)
ttemplate <typename A>
struct B { using type = typename A::type; };
 
template <
  class T,
  class   = typename T::type,      // SFINAE failure if T has no member type
  class U = typename B<T>::type    // hard error if T has no member type
                                   // (guaranteed to not occur as of C++14)
> void foo (int);
3.Type SFINAE

type sfinae都有哪些

  • attempting to instantiate a pack expansion containing multiple packs of different lengths
  • attempting to create an array of void, array of reference, array of function, array of negative size, array of non-integral size, or array of size zero.
template <int I> void div(char(*)[I % 2 == 0] = 0) {
    // this overload is selected when I is even
}
template <int I> void div(char(*)[I % 2 == 1] = 0) {
    // this overload is selected when I is odd
}
  • attempting to use a type that is not a class or enumeration on the left of a scope resolution operator ::
template <class T> int f(typename T::B*);
template <class T> int f(T);
int i = f<int>(0); // uses second overload
  • attempting to use a member of a type, where
    • the type does not contain the specified member
    • the specified member is not a type where a type is required
    • the specified member is not a template where a template is required
    • the specified member is not a non-type where a non-type is required
template <int I> struct X { };
template <template <class T> class> struct Z { };
template <class T> void f(typename T::Y*){}
template <class T> void g(X<T::N>*){}
template <class T> void h(Z<T::template TT>*){}
struct A {};
struct B { int Y; };
struct C { typedef int N; };
struct D { typedef int TT; };
struct B1 { typedef int Y; };
struct C1 { static const int N = 0; };
struct D1 { 
    template <typename T>
    struct TT
    {    
    }; 
};
int main() {
    // Deduction fails in each of these cases:
    f<A>(0); // A does not contain a member Y
    f<B>(0); // The Y member of B is not a type
    g<C>(0); // The N member of C is not a non-type
    h<D>(0); // The TT member of D is not a template
 
    // Deduction succeeds in each of these cases:
    f<B1>(0); 
    g<C1>(0); 
    h<D1>(0);
}
// todo: needs to demonstrate overload resolution, not just failure
  • attempting to create a pointer to reference
  • attempting to create a reference to void.
  • attempting to create pointer to member of T, where T is not a class type
template<typename T>
class is_class {
    typedef char yes[1];
    typedef char no [2];
    template<typename C> static yes& test(int C::*); // selected if C is a class type
    template<typename C> static no&  test(...);      // selected otherwise
  public:
    static bool const value = sizeof(test<T>(0)) == sizeof(yes);
};
  • attempting to give an invalid type to a non-type template parameter
template <class T, T> struct S {};
template <class T> int f(S<T, T()>*);
struct X {};
int i0 = f<X>(0);
// todo: needs to demonstrate overload resolution, not just failure
  • attempting to perform an invalid conversion in
    • in a template argument expression
    • in an expression used in function declaration
template <class T, T*> int f(int);
int i2 = f<int,1>(0); // can’t conv 1 to int*
// todo: needs to demonstrate overload resolution, not just failure
  • attempting to create a function type with a parameter of type void
  • attempting to create a function type which returns an array type or a function type
  • attempting to create a cv-qualified function type(until C++11)
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值