【问题标题】:MSVC 2013 'type' : is not a member of 'std::enable_if<false,void>MSVC 2013 'type' : 不是 'std::enable_if<false,void> 的成员
【发布时间】:2017-01-27 11:57:16
【问题描述】:

我使用 std::enable_if 的 SFINAE 代码在 GCC 和 Clang 中编译,但在 MSVC 2013 中不编译。

代码 (also available on cpp.sh) 是

#include <iostream>
#include <type_traits>

template <typename T, typename ... AdditionalInputs>
typename std::enable_if<sizeof...(AdditionalInputs) == 0, void>::type
CallDoDataProcessing(T var) {
    std::cout << sizeof...(AdditionalInputs) << " additional inputs" << std::endl;
}

template <typename T, typename ... AdditionalInputs>
typename std::enable_if<sizeof...(AdditionalInputs) == 1, void>::type
CallDoDataProcessing(T var) {
    std::cout << sizeof...(AdditionalInputs) << " additional inputs" << std::endl;
}

int main() {
    CallDoDataProcessing<int>(3);
    CallDoDataProcessing<int, int>(3);
    return 0;
}

在 GCC/Clang 中,这非常有效,但在 MSVC 中,我得到:

Error   1   error C2039: 'type' : is not a member of 'std::enable_if<false,void>'   c:\Users\mrussell\documents\visual studio 2013\Projects\ConsoleApplication1\ConsoleApplication1\ConsoleApplication1.cpp 5   1   ConsoleApplication1

编译和运行的输出应该是:

0 additional inputs
1 additional inputs

我在 SO 上看到过一些类似的问题,但没有一个有明确的答案或有点切题。

阅读MSVC enable_if 页面,这应该可以工作...

如何在 MSVC2013 中使用 SFINAE?

更新

请注意,这在积极的情况下确实有效。例如,如果我注释掉第一个函数以及对它的调用,那么其余的都会编译。即CallDoDataProcessing 上的enable_if&lt;true, void&gt; 确实有一个type 成员。

但是,注释掉第二个函数并调用它(因此,保留 sizeof...(AdditionalInputs) == 0 不起作用的版本。同样的错误。

这表明 sizeof...(AdditionalInputs) == 0 调用不匹配,但我不知道为什么不匹配。

【问题讨论】:

  • #include &lt;type_traits&gt;了吗?
  • @AndyG 从来没有想过,我只是尝试了一下,但似乎并没有什么不同。我将修改上面的代码以显示包含。
  • 我的第一个猜测是你需要更新 MSVC
  • @Matt:是的,这似乎是 SFINAE 的一个错误。我可以重现它。它在 VS 2015 中似乎已修复。
  • MSVC 错误除外,第一个重载格式不正确,不需要诊断,因为它的每个有效特化都需要一个空参数包。

标签: c++ c++11 visual-studio-2013 variadic-templates sfinae


【解决方案1】:

尝试标签调度。

template<std::size_t>
struct size {};

namespace details {
  template <typename T, typename ... AdditionalInputs>
  void CallDoDataProcessing(T var, size<0>) {
    std::cout << sizeof...(AdditionalInputs) << ", aka 0, additional inputs" << std::endl;
  }

  template <typename T, typename ... AdditionalInputs, std::size_t N>
  void CallDoDataProcessing(T var, size<N>) {
    std::cout << sizeof...(AdditionalInputs) << " additional inputs" << std::endl;
  }
}
template <typename T, typename ... AdditionalInputs>
void CallDoDataProcessing(T var) {
  details::CallDoDataProcessing<T, AdditionalInputs>( var, size<sizeof...(AdditionalInputs)>{} );
}

MSVC 对 SFINAE 的支持真的很差。您的代码看起来像有效的 SFINAE。 MSVC 未能做正确的事情这一事实并不令人惊讶。

根据我的经验,MSVC 在标签调度方面的工作要好得多,而且我发现它甚至可以让代码更容易理解,有时甚至会出现错误消息。

它不允许在调用函数的主体之前注意到“不,你不能这样做”,以使调用函数也声明“不,我不能完成”。

【讨论】:

  • 不错!起初我认为这也会将我限制为 AdditionalInputs 为 0 或 1,但我写了一个 example that works with N inputs
  • @matt 你回到了 SFINAE enable_if 那里。同样,MSVC 并没有很好地完成 SFINAE。它可以以令人惊讶的方式打破对代码完全不相关的更改。如果您希望N 成为12,只需使用size&lt;1&gt;size&lt;2&gt;,不要使用N,然后SFINAE 说N 应该是12。然后留下一个N 通用的,如果你需要它来处理“你的特定案例之上的所有事情”。 (当然,理想情况下,通用的可以处理所有情况,但是......)
  • 好的,我明白你的意思了。我玩过它,但习惯性地仍然过于依赖 SFINAE。我想我终于在this example 中实现了你的建议
猜你喜欢
  • 2021-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-15
相关资源
最近更新 更多