使用decltype调用基类构造器(CTAD)仅GCC/Clang支持,MSVC报错
问题背景
我正在开发一款转译为C的兴趣编程语言(项目处于Alpha早期阶段),当前处理继承与构造器逻辑。为简化编译器实现,编写的C派生类代码无需区分基类是否为模板。继承decltype推导的类型在GCC、Clang、MSVC三款编译器均可正常工作,但在初始化列表中用decltype调用基类构造器(如Child(const T& t) : decltype(Base(std::declval<T>()))(t) {})仅在GCC、Clang的C20环境可行,MSVC 19的C20环境会报“error C2059: syntax error: 'type'”错误。
问题解答
1. 哪种编译器的行为符合C++标准?
根据C++20标准,在成员初始化列表中使用decltype(...)作为基类构造的类型说明符是合法的。标准明确允许在初始化基类子对象时,使用类型表达式指定目标基类,只要该类型确实是当前类的直接基类。因此GCC和Clang的行为符合标准,MSVC的报错属于实现层面的缺陷。
2. 无需区分基类是否为模板的兼容写法
可以通过提前定义类型别名封装decltype的推导结果,避免在初始化列表中直接使用复杂的类型表达式,同时保持无需区分基类是否为模板的特性。具体代码修改如下:
#include <utility> // 示例基类(可能是普通类或模板类) template <typename T> class Base {}; template <typename T> class Child : public decltype(Base(std::declval<T>())) { private: // 提前推导并定义基类类型别名 using BaseType = decltype(Base(std::declval<T>())); public: Child(const T& t) : BaseType(t) {} };
这种写法的核心是将decltype的推导结果提前存储到类型别名BaseType中,在初始化列表中直接使用别名调用基类构造器。无论Base是普通类还是模板类,decltype(Base(std::declval<T>()))都能正确推导基类类型,同时MSVC可以正确识别初始化列表中的类型别名,避免语法错误。
该修改在GCC、Clang、MSVC的C++20环境下均可正常编译,完全满足无需区分基类是否为模板的设计需求。
内容的提问来源于stack exchange,提问作者Ehren

