fbpx
维基百科

替换失败并非错误

替换失败并非错误 (Substitution failure is not an error, SFINAE)是指C++语言在模板参数匹配失败时不认为这是一个编译错误。戴维·范德沃德英语David Vandevoorde最先引入SFINAE缩写描述相关编程技术。[1]

具体说,当创建一个重载函数的候选集时,某些(或全部)候选函数是用模板实参替换(可能的推导)模板形参的模板实例化结果。如果某个模板的实参替换时失败,编译器将在候选集中删除该模板,而不是当作一个编译错误从而中断编译过程,这需要C++语言标准授予如此处理的许可。[2] 如果一个或多个候选保留下来,那么函数重载的解析就是成功的,函数调用也是良好的。

例子 编辑

下属简单例子解释了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. 并无编译错误(即使没有 int::foo)  // thanks to SFINAE. } 

在限定名字解析时(T::foo)使用非类的数据类型,导致f<int>推导失败因为int并无嵌套数据类型foo, 但程序仍是良好定义的,因为候选函数集中还有一个有效的函数。

虽然SFINAE最初引入时是用于避免在不相关模板声明可见时(如通过包含头文件)产生不良程序。许多程序员后来发现这种行为可用于编译时内省(introspection)。具体说,在模板实例化时允许模板确定模板参数的特定性质。

例如,SFINAE用于确定一个类型是否包含特定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>(nullptr) is equal to  // sizeof(yes), the first overload worked and T has a nested type named  // foobar.  static const bool value = sizeof(test<T>(nullptr)) == sizeof(yes); }; struct foo {  typedef float foobar; }; int main() {  std::cout << std::boolalpha;  std::cout << has_typedef_foobar<int>::value << std::endl; // Prints false  std::cout << has_typedef_foobar<foo>::value << std::endl; // Prints true } 

当类型T有嵌套类型foobartest的第一个定义被实例化并且空指针常量被作为参数传入。(结果类型是yes。)如果不能匹配嵌套类型foobar,唯一可用函数是第二个test定义,且表达式的结果类型为no。省略号(ellipsis)不仅用于接收任何类型,它的转换的优先级是最低的,因而优先匹配第一个定义,这去除了二义性。

C++11的简化 编辑

C++11中,上述代码可以简化为:

#include <iostream> #include <type_traits> template <typename... Ts> using void_t = void; template <typename T, typename = void> struct has_typedef_foobar : std::false_type {}; template <typename T> struct has_typedef_foobar<T, void_t<typename T::foobar>> : std::true_type {}; struct foo {  using foobar = float; }; int main() {  std::cout << std::boolalpha;  std::cout << has_typedef_foobar<int>::value << std::endl;  std::cout << has_typedef_foobar<foo>::value << std::endl; } 

C++标准的未来版本中Library fundamental v2 (n4562) (页面存档备份,存于互联网档案馆)建议把上述代码改写为:

#include <iostream> #include <type_traits> template <typename T> using has_typedef_foobar_t = typename T::foobar; struct foo {  using foobar = float; }; int main() {  std::cout << std::boolalpha;  std::cout << std::is_detected<has_typedef_foobar_t, int>::value << std::endl;  std::cout << std::is_detected<has_typedef_foobar_t, foo>::value << std::endl; } 

Boost的使用者在boost::enable_if[3]中使用SFINAE。

参考文献 编辑

  1. ^ Vandevoorde, David; Nicolai M. Josuttis. C++ Templates: The Complete Guide. Addison-Wesley Professional. 2002. ISBN 0-201-73484-2. 
  2. ^ International Organization for Standardization. "ISO/IEC 14882:2003, Programming languages — C++", § 14.8.2.
  3. ^ Boost Enable If. [2020-08-18]. (原始内容于2008-09-05). 

替换失败并非错误, substitution, failure, error, sfinae, 是指c, 语言在模板参数匹配失败时不认为这是一个编译错误, 戴维, 范德沃德, 英语, david, vandevoorde, 最先引入sfinae缩写描述相关编程技术, 具体说, 当创建一个重载函数的候选集时, 某些, 或全部, 候选函数是用模板实参替换, 可能的推导, 模板形参的模板实例化结果, 如果某个模板的实参替换时失败, 编译器将在候选集中删除该模板, 而不是当作一个编译错误从而中断编译过程, 这需要c, 语言. 替换失败并非错误 Substitution failure is not an error SFINAE 是指C 语言在模板参数匹配失败时不认为这是一个编译错误 戴维 范德沃德 英语 David Vandevoorde 最先引入SFINAE缩写描述相关编程技术 1 具体说 当创建一个重载函数的候选集时 某些 或全部 候选函数是用模板实参替换 可能的推导 模板形参的模板实例化结果 如果某个模板的实参替换时失败 编译器将在候选集中删除该模板 而不是当作一个编译错误从而中断编译过程 这需要C 语言标准授予如此处理的许可 2 如果一个或多个候选保留下来 那么函数重载的解析就是成功的 函数调用也是良好的 例子 编辑下属简单例子解释了SFINAE struct Test typedef int foo template lt typename T gt void f typename T foo Definition 1 template lt typename T gt void f T Definition 2 int main f lt Test gt 10 Call 1 f lt int gt 10 Call 2 并无编译错误 即使没有 int foo thanks to SFINAE 在限定名字解析时 T foo 使用非类的数据类型 导致f lt int gt 推导失败因为int并无嵌套数据类型foo 但程序仍是良好定义的 因为候选函数集中还有一个有效的函数 虽然SFINAE最初引入时是用于避免在不相关模板声明可见时 如通过包含头文件 产生不良程序 许多程序员后来发现这种行为可用于编译时内省 introspection 具体说 在模板实例化时允许模板确定模板参数的特定性质 例如 SFINAE用于确定一个类型是否包含特定typedef include lt iostream gt template lt typename T gt 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 lt typename C gt static yes amp test typename C foobar template lt typename gt static no amp test If the sizeof of the result of calling test lt T gt nullptr is equal to sizeof yes the first overload worked and T has a nested type named foobar static const bool value sizeof test lt T gt nullptr sizeof yes struct foo typedef float foobar int main std cout lt lt std boolalpha std cout lt lt has typedef foobar lt int gt value lt lt std endl Prints false std cout lt lt has typedef foobar lt foo gt value lt lt std endl Prints true 当类型T有嵌套类型foobar test的第一个定义被实例化并且空指针常量被作为参数传入 结果类型是yes 如果不能匹配嵌套类型foobar 唯一可用函数是第二个test定义 且表达式的结果类型为no 省略号 ellipsis 不仅用于接收任何类型 它的转换的优先级是最低的 因而优先匹配第一个定义 这去除了二义性 C 11的简化 编辑C 11中 上述代码可以简化为 include lt iostream gt include lt type traits gt template lt typename Ts gt using void t void template lt typename T typename void gt struct has typedef foobar std false type template lt typename T gt struct has typedef foobar lt T void t lt typename T foobar gt gt std true type struct foo using foobar float int main std cout lt lt std boolalpha std cout lt lt has typedef foobar lt int gt value lt lt std endl std cout lt lt has typedef foobar lt foo gt value lt lt std endl C 标准的未来版本中Library fundamental v2 n4562 页面存档备份 存于互联网档案馆 建议把上述代码改写为 include lt iostream gt include lt type traits gt template lt typename T gt using has typedef foobar t typename T foobar struct foo using foobar float int main std cout lt lt std boolalpha std cout lt lt std is detected lt has typedef foobar t int gt value lt lt std endl std cout lt lt std is detected lt has typedef foobar t foo gt value lt lt std endl Boost的使用者在boost enable if 3 中使用SFINAE 参考文献 编辑 Vandevoorde David Nicolai M Josuttis C Templates The Complete Guide Addison Wesley Professional 2002 ISBN 0 201 73484 2 International Organization for Standardization ISO IEC 14882 2003 Programming languages C 14 8 2 Boost Enable If 2020 08 18 原始内容存档于2008 09 05 取自 https zh wikipedia org w index php title 替换失败并非错误 amp oldid 69280297, 维基百科,wiki,书籍,书籍,图书馆,

文章

,阅读,下载,免费,免费下载,mp3,视频,mp4,3gp, jpg,jpeg,gif,png,图片,音乐,歌曲,电影,书籍,游戏,游戏。