我可以消除重载模板功能与更受约束的模板功能之间的歧义吗?

Bar*_*icz 7 c++ c++11

代码

#include <iostream>
#include <type_traits>

template<typename T,
         typename = typename std::enable_if<std::is_pod<T>::value>::type
         >
T foo(T t) { return t; }

template<typename T>
void foo(T t) { }

int main()
{
    foo<int>(5);
}
Run Code Online (Sandbox Code Playgroud)

错误

main.cpp: In function 'int main()':
main.cpp:14:15: error: call of overloaded 'foo(int)' is ambiguous
     foo<int>(5);
               ^
main.cpp:14:15: note: candidates are:
main.cpp:7:3: note: T foo(T) [with T = int; <template-parameter-1-2> = void]
 T foo(T t) { return t; }
   ^
main.cpp:10:6: note: void foo(T) [with T = int]
 void foo(T t) { }
      ^
Run Code Online (Sandbox Code Playgroud)

这个问题

是否有可能解决代码中的错误?

Jon*_*ely 15

使用SFINAE约束函数不会引入排序,它只是意味着约束函数可调用或不可调用,因此当启用第一个重载时,您有两个不明确的函数.

最简单的解决方案是使用相同约束的反转来禁用第二个重载,这样对于给定类型只有一个是可行的.要完成这项工作,您需要移动enable_if到返回类型,而不是默认模板参数(因为默认模板参数不是函数签名的一部分,因此不能用于重载,只能用SFINAE约束).此解决方案不适用于大量重载,除非您可以为每个重载提供单独的谓词(即类型特征的组合),这样任何参数类型都不会匹配多个谓词.这意味着谓词必须是互斥的,你不能让谓词测试一个概念,比如有符号整数类型,这是另一个测试概念的更精炼版本,例如整数类型,因为这两个谓词都适用于int多个谓词功能将启用.

C++ Concepts是比SFINAE更好的解决方案的一个重要原因是受概念约束的函数是有序的,因此更受约束的函数比较少受约束的函数更好地匹配.这意味着您不需要玩这些SFINAE游戏并且具有相互排斥的约束,编译器将做正确的事情.

  • 关于C++概念的有趣注释.我认识的大多数人只是认为它只是SFINAE的语法糖而与原始SFINAE没有实质性区别.不知道情况并非如此. (6认同)

Nia*_*all 6

将相同的SFINAE应用于备用方法,只需将其反转(并将其移至返回类型); 即禁用另一个.

template<typename T>
typename std::enable_if<std::is_pod<T>::value, T>::type
foo(T t) { return t; }

template<typename T>
typename std::enable_if<!std::is_pod<T>::value, void>::type
foo(T t) { }
Run Code Online (Sandbox Code Playgroud)

你提到会有很多超载,所以这可能很麻烦...你的里程可能会有所不同.

注意,为什么只有2?最初的问题是2,但这里的问题更多是涉及模板约束的许多重载之间的排序.当只有少量重载(具有更易于管理的SFINAE约束)时,这个答案留给更经典的解决方案.