我想专门化 getVector
成员函数,我正在尝试使用 SFINAE 来实现此目的。但仅当 Dim 为 3 或更大时才有效。
template <size_t Dim>
class Mat
{
...
template <size_t VDim, typename enable_if<(Dim > 1 && VDim == 0)>::type* = nullptr>
void getVectorBegin(const array<size_t, Dim - 1>& indexAfter) const;
template <size_t VDim, typename enable_if<(Dim > 2 && 0 < VDim && VDim < Dim-1)>::type* = nullptr>
void getVectorBegin(const array<size_t, VDim>& indexBefore, const array<size_t, Dim - VDim - 1>& indexAfter) const;
template <size_t VDim, typename enable_if<(Dim > 1 && VDim == Dim-1)>::type* = nullptr>
void getVectorBegin(const array<size_t, Dim - 1>& indexBefore) const;
};
Mat<3> m;
Mat<2> m; // error C2039: 'type': is not a member of 'std::enable_if<false,_Ty>'
最佳答案
这会很棘手。
我相信你的代码对于 Dim>=2
来说是可以的但当给出 Dim<=1
时,它的格式不正确。参数,不需要诊断,但由于不同的原因,您的编译器正在提示。
对于Dim>=2
它是正确的,但你的编译器(我猜是 MSVC++)在 Dim==2
中提示案件。鉴于错误描述,我认为原因是它错误地将 enable_if
中的 && 表达式短路。条件,当 Dim > x
时,将它们解释为仅依赖于类模板参数的值是假的。解决方法是移动 Dim > x
检查为 && 表达式的最后一项。
详细来说,这种情况在概念上类似于以下代码片段:
template <size_t N>
class foo
{
template <typename E = enable_if_t<(N>0)>>
void bar();
};
foo<1> f1;
foo<0> f0; // fails
这里是 foo
的实例触发其成员声明(但不是定义)的实例化(请参阅[temp.inst]#1);但是,只有依赖于成员模板参数的名称和表达式的检查才会在各自的实例化点被推迟。这里,类型名称enable_if_t<(N>0)>
不依赖于任何 bar()
模板参数( N
属于 foo
的模板参数列表)因此是不依赖的,导致 enable_if<false>::type
当N == 0
,所以报错。
回到你的代码,考虑:
[temp.dep.constexpr]#1 Except as described below, a constant expression is value-dependent if any subexpression is value-dependent
并且没有任何地方提到短路运算符作为异常(exception)。所以,表达式,比如 Dim > 1 && VDim == 0
即使 Dim<=1
也是值相关的;因此,在替换 VDim
之前不会发生错误(SFINAE 适用的情况)。事实上,gcc 和 clang agree接受您的代码。
也就是说,当 Dim<=1
第一和第三getVectorBegin
重载实际上声明了功能等效的成员模板(参见[temp.over.link]#6),所以我认为在这种情况下它的格式不正确。
关于c++ - SFINAE 关于模板成员重载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47991321/