了解默认模板参数何时是重新定义以及何时不在 SFINAE 技术中

问题描述

SFINAE 技术是使用认类来启用/禁用功能。但是,这不适用于重载函数,导致“模板参数重新定义认参数”:

template <class T,class = std::enable_if_t<std::is_integral_v<T>>>
auto foo(T) { return 1; }

template <class T,class = std::enable_if_t<std::is_floating_point_v<T>>>
auto foo(T) { return 2; }

// error template parameter redefines default argument"

常见的解决方法是使用认的非类型模板参数:

template <class T,std::enable_if_t<std::is_integral_v<T>,int> = 0>
auto foo(T) { return 1; }

template <class T,std::enable_if_t<std::is_floating_point_v<T>,int> = 0>
auto foo(T) { return 2; }

// works

这仅在条件“不同”时有效。但是理解什么时候条件“不同”就不是那么简单了。

从最明显的例子开始(相同(token by token)条件):

template <class T,T> = 0>
auto foo(T) { return 1; }

template <class T,T> = 0>
auto foo(T) { return 2; }

// error template parameter redefines default argument"

有两个不同的非依赖条件,计算结果相同:

constexpr bool true_1 = true;
constexpr bool true_2 = true;

template <class T,std::enable_if_t<true_1,std::enable_if_t<true_2,T> = 0>
auto foo(T) { return 2; }

// error template parameter redefines default argument"

有两个不同的依赖条件,评估为相同的值:

template <class T> constexpr bool true_1 = true;
template <class T> constexpr bool true_2 = true;

template <class T,std::enable_if_t<true_1<T>,T> enable = 0>
auto foo(T) { return 1; }

template <class T,std::enable_if_t<true_2<T>,T> enable = 0>
auto foo(T) { return 2; }

// works
// (of course will give ambiguous call error when trying to call it,//  but the point here is you are allowed to declare them like this)

在最后一个示例中,如果我调用 foo(即 foo(24)),两个重载都具有完全相同的参数和模板参数:

错误:对 'foo' 的调用不明确

return foo(12);
       ^~~

注意:候选函数[with T = int,enable = 0]

auto foo(T) { return 1; }
     ^

注意:候选函数[with T = int,enable = 0]

auto foo(T) { return 2; }
     ^

这似乎有效地实例化了两个相同的重载(根据声明,而不是定义)。

我的所有问题都非常相关,所以我在这里问所有问题:

  1. 当两个非类型模板参数不被视为重新定义时,具体的规则是什么?
  2. 标准如何处理两个声明相同的重载(如上一个示例)
  3. 为什么这适用于非类型模板参数,而不适用于类型模板参数?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)