派生类Aggregate initialization编译失败:VS2017与在线GDB均报错
为什么你的代码无法编译?
咱们一步一步拆解这个问题:
首先,你遇到的编译错误核心和C++标准中「聚合类型」的定义变化直接相关:
1. C11/C14的严格限制
在C11和C14标准里,聚合类型的定义卡得很死:聚合类型不能有任何基类。你的Gen结构体继承了std::iterator,所以它直接被踢出了聚合类型的范畴。
而你用的Gen<int>{10}或者Gen<int>{ {}, 10 }属于聚合初始化——这种初始化方式只给聚合类型用(比如没有自定义构造函数的简单结构体、数组)。因为Gen不是聚合类型,编译器找不到匹配的构造函数处理这个初始化列表,自然就报错了。
2. C++17的规则放宽
到了C++17,标准对聚合类型的定义松了绑:允许聚合类型公有、非虚拟地继承其他聚合类型,只要基类本身也是聚合类型。
那std::iterator算不算聚合类型?看它的本质:就是个包含五个类型别名的空结构体,没有用户声明的构造函数,没有非静态数据成员,所有成员都是public的——完全符合聚合类型的要求。所以在C++17及以后的标准里,你的代码是完全合法的,应该能正常编译。
3. 为什么VS2017和在线GDB不行?
- VS2017:它对C17的支持是逐步迭代的,早期版本可能没实现聚合继承这个特性,而且默认的C标准大概率还是C14。你需要手动开启C17:打开项目属性 → C/C++ → 语言 → C标准,选择「ISO C17标准(/std:c++17)」。即使开启了,某些VS2017版本对这个特性的支持可能还有小bug。
- 在线GDB:多数在线编译环境默认用C11或C14标准,你得手动加编译选项
-std=c++17才能启用C++17特性。
解决方案
如果需要兼容旧标准(C11/C14),最简单的办法是给Gen加个构造函数:
template<typename T> struct Gen : public std::iterator<std::input_iterator_tag, T> { T value; // 显式构造函数,避免意外隐式转换 explicit Gen(T v) : value(v) {} // 保留默认构造函数(如果需要默认初始化) Gen() = default; };
这样你就能用Gen<int> g(10);或者Gen<int> g = Gen<int>(10);来初始化对象了。
如果只需要支持C17及以上,确保编译器开启了C17标准,你的原代码就能正常工作。
内容的提问来源于stack exchange,提问作者Serve Laurijssen
相关产品推荐
相关产品推荐

