2016-03-02 52 views
14

考虑下面的代码:为什么void_t <>检测方式不适用于gcc-4.9?

#include <iostream> 
#include <type_traits> 

struct Test { Test& operator++(); }; 
struct NoIncrement { }; 

template <typename...> using void_t = void; 

template <class, class=void_t<>> 
struct has_pre_increment_member : std::false_type { }; 

template <class T> 
struct has_pre_increment_member<T, void_t<decltype(++std::declval<T&>())>> 
    : public std::true_type { }; 

int main() { 
    std::cout << has_pre_increment_member<Test>::value << " "; 
    std::cout << has_pre_increment_member<NoIncrement>::value << std::endl; 
} 

随着克++ 5及之后的版本(以及-std = C++ 14标志,当然),该代码输出

1 0 

,它应。随着G ++ 4.9版本(和-std = C++ 14标志),但是,它输出

1 1 

两个要求使用相同的语言标准是,有啥这里的问题?

+2

你使用的是4.9.0还是比它高?我已经看到4.9.0中的一些错误,如果你转到4.9.2,那么这些错误是固定的。 – NathanOliver

+0

4.9.3确切地说 –

+0

那么这就是我所能贡献的。如果它让你跌倒得更好,它也可以在叮当中奏效。 – NathanOliver

回答

16

这是作为CWG Issue 1558的结果,现在被认为是gcc中的错误(特别是64395 - 当前已修复)。这个问题背后的想法是,既然你不实际使用的模板参数在这里:

template <typename...> using void_t = void; 

没有替换故障无论你尝试在传递什么类型或表达式

值得庆幸的是,有一个简单的解决方法,不涉及升级您的编译器。我们可以重写void_t实际使用它的参数包,从而触发替换故障:

namespace void_details { 
    template <class... > 
    struct make_void { using type = void; }; 
} 

template <class... T> using void_t = typename void_details ::make_void<T...>::type; 

这会让你的例子做跨所有版本的GCC我想正确的事情。

相关问题