问题描述
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)
),两个重载都具有完全相同的参数和模板参数:
return foo(12);
^~~
注意:候选函数[with T = int,enable = 0]
auto foo(T) { return 1; }
^
注意:候选函数[with T = int,enable = 0]
auto foo(T) { return 2; }
^
这似乎有效地实例化了两个相同的重载(根据声明,而不是定义)。
我的所有问题都非常相关,所以我在这里问所有问题:
- 当两个非类型模板参数不被视为重新定义时,具体的规则是什么?
- 标准如何处理两个声明相同的重载(如上一个示例)
- 为什么这适用于非类型模板参数,而不适用于类型模板参数?
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)