为什么void_t<>检测习惯用语不适用于 gcc-4.9?
Why does the void_t<> detection idiom not work with 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;
}
对于 g++ 版本 5 及更高版本(当然还有 -std=c++14 标志),此代码输出
1 0
理应如此。 但是,对于 g++ 版本 4.9(和 -std=c++14 标志),它会输出
1 1
两者都声称使用相同的语言标准,那么这里有什么问题呢?
这是
CWG问题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 版本中做正确的事情。
相关文章:
- OpenGL/Glew C++纹理不适用
- 十进制到二进制的实现不能完全适用于我大学的检查器。问题或提示可能是什么
- 保证复制省略不应该适用吗?
- 当我在 windows7 中安装程序时,我指定的字体大小不适用
- 使用程序集嵌入数据时"Undefined reference"错误,使用适用于窗口的 mingw-w64 编译(COFF 而不是 ELF)
- accelerator.cu(8): 错误:属性"managed"在这里不适用?
- 为什么 std::vector 适用于类定义中的不完整类型?
- typedef X=<T>T::UserType1,但如果不适用,typedef X<T>=UserType2
- 为什么编译器在使用检测习惯用语时不提示双重定义?
- 为什么哈希<常量字符*>适用于字符串而不是字符串变量?
- 用C++编写一个程序,对一个简单的序列求和:1/N + 2/N-1 + 3/N-2+ ...不适用
- Lambda适用于最新的Visual Studio,但在其他地方不起作用
- 我该如何文档文档以使文档适用于类成员而不是匿名类型
- 计算 c# 中二进制文件符号的频率不起作用,但适用于等效的 c++ 代码
- 为什么 fstream.open(文件名) 适用于文字而不是生成的字符串?
- Google Play游戏服务(GPGS)实时多人游戏(RTMP)在Android上永远不会匹配(iOS适用)
- SFINAE在这里不适用吗?
- 为什么在适用时不暗示 constexpr?
- 当是复制和交换习语不适用
- 在函数实参中使用模板形参不适用gcc4.8