为何以下代码在GCC、Clang可编译通过但在Visual Studio中编译失败?
为何以下代码在GCC、Clang可编译通过但在Visual Studio中编译失败?
嘿,我来帮你拆解这个问题~你贴的这段代码(我先补全了可能截断的继承部分)在GCC和Clang能正常编译,但到了VS就报错,核心原因是不同编译器对C++模板实例化时机的处理差异,具体来看:
先看完整的代码(假设你输入时截断了继承的模板参数):
#include <type_traits> template <typename serialisable_t, int version_num_arg, bool bForceSerialisingWithMemcpy> struct Serialisable_Trait { static constexpr inline int version_num = version_num_arg; static constexpr inline bool bIsSerialisableWithMemcpy = std::is_trivially_copyable_v<serialisable_t> || bForceSerialisingWithMemcpy; }; // 补全的派生类定义 struct MySerialisableType : public Serialisable_Trait<MySerialisableType, 1, false> {};
问题根源
说白了,问题出在基类模板里用了还没完全定义的派生类类型:当我们定义MySerialisableType时,它继承自Serialisable_Trait<MySerialisableType, ...>,此时MySerialisableType还处于“不完整类型”的状态(因为我们正在写它的定义)。
- GCC和Clang采用了“懒加载”式的模板实例化:它们会等到
MySerialisableType完全定义完成后,才去计算基类里的bIsSerialisableWithMemcpy常量。这时候MySerialisableType已经是完整类型了,std::is_trivially_copyable_v就能正常工作。 - 但Visual Studio的编译器更“急性子”:它在处理继承的时候,会立刻尝试实例化基类的所有成员。这时候
MySerialisableType还不完整,而std::is_trivially_copyable_v要求必须传入完整类型,所以直接触发编译错误。
解决办法
给你两个实用的修改方案,都能让VS乖乖编译通过:
方案一:把常量改成constexpr函数延迟求值
把bIsSerialisableWithMemcpy改成一个constexpr成员函数,这样它只会在被实际调用的时候才去计算值,而不是在基类实例化时就执行:
#include <type_traits> template <typename serialisable_t, int version_num_arg, bool bForceSerialisingWithMemcpy> struct Serialisable_Trait { static constexpr inline int version_num = version_num_arg; // 改成函数,延迟到调用时求值 static constexpr bool isSerialisableWithMemcpy() { return std::is_trivially_copyable_v<serialisable_t> || bForceSerialisingWithMemcpy; } }; struct MySerialisableType : public Serialisable_Trait<MySerialisableType, 1, false> {};
方案二:用辅助模板层延迟实例化
加一个辅助模板,把类型检查的逻辑放到里面,让它的实例化时机延后:
#include <type_traits> // 辅助模板,负责延迟求值类型检查 template <typename T, bool Force> struct MemcpyCheck { static constexpr bool value = std::is_trivially_copyable_v<T> || Force; }; template <typename serialisable_t, int version_num_arg, bool bForceSerialisingWithMemcpy> struct Serialisable_Trait { static constexpr inline int version_num = version_num_arg; // 借助辅助模板延迟实例化 static constexpr inline bool bIsSerialisableWithMemcpy = MemcpyCheck<serialisable_t, bForceSerialisingWithMemcpy>::value; }; struct MySerialisableType : public Serialisable_Trait<MySerialisableType, 1, false> {};
内容来源于stack exchange
相关产品推荐
相关产品推荐

