c++ - 当一个条件分支从基类继承时,为什么这个 SFINAE 不能与 enable_if 一起使用?
问题描述
#include <bits/stdc++.h>
#include <type_traits>
// Type your code here, or load an example.
template <typename Types>
class C1 {
public:
using A=typename Types::A;
using B=typename Types::B;
template <typename Dummy = void>
inline typename std::enable_if<std::is_same<A, B>::value, Dummy>::type f() { }
};
template <typename Types>
class C2 : public C1<Types> {
public:
using A=typename Types::A;
using B=typename Types::B;
template <typename Dummy = void>
inline typename std::enable_if<!std::is_same<A, B>::value, Dummy>::type f() { }
};
template <typename Types>
class C3 : public C2<Types> {
public:
using A=typename Types::A;
using B=typename Types::B;
};
struct Types{
using A = int;
using B = int;
};
int main() {
C3<Types> c;
c.f();
return 0;
}
当我在 A 和 B 不相同的情况下尝试编译上述代码时,出现以下错误:
<source>: In function 'int main()':
<source>:42:9: error: no matching function for call to 'C3<Types>::f()'
42 | c.f();
| ^
<source>:23:77: note: candidate: 'template<class Dummy> typename std::enable_if<(! std::is_same<typename Types::A, typename Types::B>::value), Dummy>::type C2<Types>::f() [with Dummy = Dummy; Types = Types]'
23 | inline typename std::enable_if<!std::is_same<A, B>::value, Dummy>::type f() { }
| ^
<source>:23:77: note: template argument deduction/substitution failed:
<source>: In substitution of 'template<class Dummy> typename std::enable_if<false, Dummy>::type C2<Types>::f<Dummy>() [with Dummy = void]':
<source>:42:9: required from here
<source>:23:77: error: no type named 'type' in 'struct std::enable_if<false, void>'
请注意,我提供的代码不是我使用的确切代码,而是一个最小的可重现示例
编辑:使用godbolt代替前面的一个最小的可重复示例,以便更好地了解情况
解决方案
与此类问题一样,它归结为 SFINAE 的定义。S 代表“替换”,它发生在我们试图实例化的模板中。该模板是成员f
,而不是C
。
尽管C
也是一个模板,并且两者A
都是B
依赖类型,但在实例化时C
它们不是依赖类型。f
他们已经为人所知。因此,条件std::is_same<A, B>::value
不是依赖于任何模板参数的值f
。它不依赖于变电站f
。这会触发 C++11 标准中的以下条款(取自发布前的最后一稿):
[temp.res](强调我的)
8知道哪些名称是类型名称可以检查每个模板定义的语法。对于可以生成有效特化的模板定义,不应发出诊断。 如果无法为模板定义生成有效的特化,并且该模板未实例化,则模板定义格式错误,无需诊断。
这意味着无论Types
是什么,如果它不支持 的条件f
,那么f
(甚至没有被实例化)的定义在C
实例化时就已经是不正确的。通常不需要诊断(因为在一般情况下检查它是棘手的),但编译器可以经常及早诊断它,并会告诉你问题。
现在,至于如何修复它,只需使f
value 的条件依赖于它自己的模板参数。一个简单的重写可以
template <bool Dummy = std::is_same<A, B>::value>
inline auto f(vector<int>& ctx, const string& r) ->
typename std::enable_if<Dummy>::type { }
现在条件取决于正确上下文中的变电站。
当然,即使您修复了 SFINE 问题,您仍然需要确保重载集由正确的成员组成。f
inC2
隐藏了f
in C1
。添加 using 声明,C2
使其仍然是候选对象
using C1<Types>::f;
推荐阅读
- azure-data-factory - Epoch timestamp in Data factory
- reactjs - 将 React 应用程序嵌入到其他 React 应用程序
- php - Get latest transaction details from loanhist
- regex - html - 输入标签限制为字母和数字
- python - Numpy:根据满足条件的组拆分数组
- c++ - 反转字符串时如何初始化数组
- python-3.x - URL列表中的for循环
- angular - Angular 5+ Two Methods for Component Communication and Possible Issues
- vue.js - Webpack 4+ 配置
- angular - 错误嵌套路由