MSVC 2013&#39; type&#39; :不是&#39; std :: enable_if <false,void>的成员

时间:2016-09-19 17:47:52

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

我的SFINAE代码使用std::enable_if编译在GCC&amp; 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?

更新

就像一张纸条,这确实适用于积极的情况。例如,如果我注释掉第一个函数,并调用它,那么其余函数就会编译。即enable_if<true, void>上的CallDoDataProcessing确实有type成员。

然而,注释掉第二个函数并调用它(所以,将版本保留在sizeof...(AdditionalInputs) == 0不起作用。相同的错误。

这表明sizeof...(AdditionalInputs) == 0来电未被匹配,但我无法弄清楚它为什么不会。

1 个答案:

答案 0 :(得分:7)

尝试标记调度。

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)>{} );
}

SFINAE受到MSVC的极大支持。您的代码看起来像有效的SFINAE。 MSVC未能做正确的事情并不令人惊讶。

根据我的经验,MSVC使用标签调度更好地工作 ,我发现它甚至会导致更容易理解代码甚至错误消息。

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