c – 为什么SFINAE在默认函数参数中不在右侧工作?

c – 为什么SFINAE在默认函数参数中不在右侧工作?,第1张

概述我有这个代码: struct My{ typedef int foo;};struct My2{};template <typename T>void Bar(const T&, int z = typename T::foo()){ std::cout << "My" << std::endl; }void Bar(...){ std::co 我有这个代码:
struct My{   typedef int foo;};struct My2{};template <typename T>voID bar(const T&,int z = typename T::foo()){    std::cout << "My" << std::endl; }voID bar(...){    std::cout << "..." << std::endl; }int main() {    My my;    bar(my); // OK    My2 my2;    bar(my2); // Compile error: no type named ‘foo’ in ‘struct My2’    return 0;}

我想,如果一些类T没有typedef foo里面,编译器应该排除第一个重载,并选择带有省略号的重载.但是我在MSVC,gcc和clang上检查这个代码,我在这些编译器上收到编译错误.为什么SFINAE在这种情况下不起作用?

解决方法 z的类型不受模板替换,它总是int.这意味着SFINAE没有机会,而是在尝试解析T :: foo作为默认值时,得到编译器错误.默认参数不参与重载分辨率,而是仅在函数调用缺失时被实例化.该标准的第14.7.1节(第13/14段)描述了这种行为,但并没有给出缺乏SFINAE的理由.

通过将z的类型设置为模板参数,可以允许SFINAE发生,如下所示:

(实例:http://ideone.com/JynMye)

#include <iostream>struct My{   typedef int foo;};struct My2{};template<typename T,typename I=typename T::foo> voID bar(const T&,I z = I()){    std::cout << "My\n";}voID bar(...){    std::cout << "...\n";}int main() {    My my;    bar(my); // OK    My2 my2;    bar(my2); // Also OK    return 0;}

这将使用第一个呼叫的“我的”版本,第二个呼叫的“…”版本.输出是

My...

然而,如果voID bar(…)是一个模板,无论什么原因,“My”版本永远都不会有机会:

(实例:http://ideone.com/xBQiIh)

#include <iostream>struct My{   typedef int foo;};struct My2{};template<typename T,I z = I()){    std::cout << "My\n";}template<typename T> voID bar(T&){    std::cout << "...\n";}int main() {    My my;    bar(my); // OK    My2 my2;    bar(my2); // Also OK    return 0;}

在这两种情况下,都会调用“…”版本.输出为:

......

一个解决方案是使用类模板(部分)专业化;提供“…”版本作为基础,第二个参数的类型默认为int,“My”版本作为专用化,第二个参数是typename T :: foo.结合一个简单的模板函数来推导T并发送到适当的类’成员函数,这产生了期望的效果:

(实例:http://ideone.com/FanLPc)

#include <iostream>struct My{   typedef int foo;};struct My2{};template<typename T,typename I=int> struct call_traits {    static voID bar(...)    {        std::cout << "...\n";    }};template<typename T> struct call_traits<T,typename T::foo> {    static voID bar(const T&,int z=typename T::foo())    {        std::cout << "My\n";    }};template<typename T> voID bar(const T& t){    call_traits<T>::bar(t);}int main() {    My my;    bar(my); // OK    My2 my2;    bar(my2); // Still OK    return 0;}

这里输出的是:

My...
总结

以上是内存溢出为你收集整理的c – 为什么SFINAE在默认函数参数中不在右侧工作?全部内容,希望文章能够帮你解决c – 为什么SFINAE在默认函数参数中不在右侧工作?所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/langs/1233017.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-06-06
下一篇2022-06-06

发表评论

登录后才能评论

评论列表(0条)

    保存