c++ - SFINAE 关于模板成员重载

标签 c++ class templates template-specialization sfinae

我想专门化 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>::typeN == 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/

相关文章:

c++ - 使用 C++ 替换文件中的字符

java - 在单独的类中使用 ActionListener

c++ - 我可以有一个带有可变对象的模板吗?

c++ - 创建具有有限参数的 std::function 类型

c++ - 可变参数模板问题

c++ - 您如何在 DirectX 和 C++ 中执行 LoD?

c++ - 仅在使用时如何在成员函数中进行静态断言?

c++ - Qtableview搜索栏

javascript - 粘性导航栏在滚动到顶部时更改文本/背景颜色,.addclass 不起作用?

c++ - 继承中可用性和可访问性的区别