【问题标题】:SFINAE on template member overloadingSFINAE 关于模板成员重载
【发布时间】:2018-06-08 01:09:05
【问题描述】:

我想专门研究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>x”检查作为最后一个 && 术语?我不确定编译器是否正确,或者它是否只是定义的实现,但它可能会使 enable_if 条件短路并认为其值不依赖于 VDim,因此在成员声明实例化期间给出编译器错误(即在 Mat 实例化点)
  • 有些东西你没有给我们看。如果不使用模板类的成员函数,则不会实例化它们。你能告诉我们调用站点吗?
  • @papagaga 这并不完全正确,成员函数声明(但不是它们的定义)在类模板时被实例化。因此,如果声明包含一个表达式,该表达式在类模板参数上,并且该表达式结果格式错误,即使该函数未“使用”也会引发错误...
  • 它们都编译得很好。 ideone.com/g4rRMu
  • @MassimilianoJanes:在这种情况下,getVectorBegin 不仅仅依赖于类模板参数,是吗?但感谢您的精确。 / @嗨,我是 Frogatto:那是因为在调用 getVectorBegin 的构造函数中有一些东西,我们在 sn-p 中看不到。

标签: c++ class templates template-specialization sfinae


【解决方案1】:

这会很棘手。

我相信你的代码对于Dim&gt;=2 来说是可以的,但是当给定Dim&lt;=1 参数时它的格式不正确,不需要诊断,但是由于不同的原因你的编译器抱怨。


对于Dim&gt;=2,它是正确的,但是您的编译器(我猜是MSVC++)在Dim==2 的情况下会抱怨。鉴于错误描述,我想原因是它错误地将enable_if 条件中的 && 表达式短路,当Dim &gt; x 为错误的。解决方法是将 Dim &gt; x 检查作为 && 表达式的最后一项。

细说一下,概念上类似于下面的代码sn-p:

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&lt;(N&gt;0)&gt; 确实 依赖于任何bar() 模板参数(N 属于foo 的模板参数列表)因此是非依赖的,导致@987654335 @当N == 0,所以报错。


回到你的代码,考虑一下:

[temp.dep.constexpr]#1 除下文所述外,常量表达式是值相关的如果任何子表达式是值相关的

并且没有任何地方提到短路运算符作为例外。因此,即使Dim&lt;=1,表达式Dim &gt; 1 &amp;&amp; VDim == 0 也是值相关的;因此,在替换 VDim(适用 SFINAE)之前不会发生错误。事实上,gcc 和 clang agree 都在接受你的代码。

也就是说,当Dim&lt;=1 第一个和第三个getVectorBegin 重载实际上声明功能等效 成员模板时(参见[temp.over.link]#6) ,所以我认为在这种情况下它的格式不正确。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多