参考
Substitution failure is not an error
C++ Template的选择特化
C++模板进阶指南:SFINAE
std::enable_if
SFINAE
SFINAE
替换失败不是错误(SFINAE)是指C ++中模板参数的无效替换本身并不是错误的情况。David Vandevoorde首先引入了缩写词SFINAE来描述相关的编程技术。[1]
具体地,当创建用于重载解析的候选集时,该集合的一些(或全部)候选者可能是实例化模板的结果,该模板实例化了(可能推导的)模板参数来代替相应的模板参数。如果在将一组参数替换为任何给定模板的过程中发生错误,则编译器会从候选集中消除潜在的重载,而不会因编译错误而停止,前提是替换错误是C ++标准授予此类处理的错误。[2]如果剩下一个或多个候选并且重载解析成功,则调用格式正确
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| struct Test { typedef int foo; };
template <typename T> void f(typename T::foo) {}
template <typename T> void f(T) {}
int main() { f<Test>(10); f<int>(10); }
|
此规则在函数模板的重载解析期间适用:当用显式指定的或推导的类型代替template参数失败时,将从重载集中放弃专业化,而不会引起编译错误。
替代发生在:
- 函数类型中使用的所有类型(包括返回类型和所有参数的类型)
- 模板参数声明中使用的所有类型
//(自C ++ 11起)
- 函数类型中使用的所有表达式
- 模板参数声明中使用的所有表达式
//自C ++ 20起)
模板特化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
|
#include <iostream> struct mytrue { public: static const int value = 1; }; struct myfalse { public: static const int value = 0; };
template<typename T> struct dd{};
template<> struct dd<std::false_type> : myfalse { };
template<> struct dd<std::true_type> : mytrue { };
int main() { std::cout << dd<std::true_type>::value << std::endl; std::cout << dd<std::false_type>::value << std::endl; }
|
enable_if
1 2 3 4 5 6 7 8 9 10 11
| template<bool, typename _Tp = void> struct enable_if { };
template<typename _Tp> struct enable_if<true, _Tp> { typedef _Tp type; };
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| #include <iostream>
template <bool, typename T = void> struct my_if{};
template <typename T> struct my_if<true, T>{ typedef T type; };
template <typename T> struct my_if<false, T>{ typedef T* type; };
int main() { std::cout << std::is_same<void, my_if<true>::type>() << std::endl; std::cout << std::is_same<void *, my_if<false>::type>() << std::endl;
std::cout << std::is_same<int, my_if<true, int>::type>() << std::endl; std::cout << std::is_same<int *, my_if<false, int>::type>() << std::endl; }
|
总结
模板特化和SFINAE挺复杂的,目前没有精力挖的太深,掌握大概就行了。
ending