VS2019/2022中前置声明下variant与vector编译问题咨询
问题
在Visual Studio 2019或2022中,以下代码里变量a和b可以正常编译,但变量c无法编译,报错信息如下,请问原因是什么?有哪些解决办法?
#include <variant> #include <vector> struct data; // 定义在另一文件中 std::variant<data>* a; // 正常 std::vector<data*> b; // 正常 std::vector<std::variant<data>*> c; // 错误 C2139: 'data': 未定义的类不能作为编译器固有类型特性'__is_trivially_destructible'的参数
完整错误信息:
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\include\variant(931,60): error C2139: 'data': an undefined class is not allowed as an argument to compiler intrinsic type trait '__is_trivially_destructible' 1>C:\Temp\test2019\main.cpp(4): message : see declaration of 'data' 1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\include\variant(931): message : see reference to variable template 'const bool conjunction_v<std::is_trivially_destructible<data> >' being compiled 1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\include\variant(1006): message : see reference to alias template instantiation 'std::_Variant_destroy_layer<data>' being compiled 1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\include\vector(1667): message : see reference to class template instantiation 'std::variant<data>' being compiled 1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\include\vector(1665): message : while compiling class template member function 'void std::vector<std::variant<data> *,std::allocator<std::variant<data> *>>::_Destroy(std::variant<data> **,std::variant<data> **)' 1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\include\vector(1751): message : see reference to function template instantiation 'void std::vector<std::variant<data> *,std::allocator<std::variant<data> *>>::_Destroy(std::variant<data> **,std::variant<data> **)' being compiled 1>C:\Temp\test2019\main.cpp(8): message : see reference to class template instantiation 'std::vector<std::variant<data> *,std::allocator<std::variant<data> *>>' being compiled 1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\include\xsmf_control.h(60,19): error C2139: 'data': an undefined class is not allowed as an argument to compiler intrinsic type trait '__is_constructible' 1>C:\Temp\test2019\main.cpp(4): message : see declaration of 'data' 1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\include\xsmf_control.h(60): message : see reference to variable template 'const bool conjunction_v<std::is_move_constructible<data>,std::negation<std::conjunction<std::is_trivially_move_constructible<data> > > >' being compiled 1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\include\xsmf_control.h(97): message : see reference to alias template instantiation 'std::_SMF_control_move<std::_Variant_destroy_layer_<data>,data>' being compiled 1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\include\xsmf_control.h(39,19): error C2139: 'data': an undefined class is not allowed as an argument to compiler intrinsic type trait '__is_constructible' 1>C:\Temp\test2019\main.cpp(4): message : see declaration of 'data' 1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\include\xsmf_control.h(39): message : see reference to variable template 'const bool conjunction_v<std::is_copy_constructible<data>,std::negation<std::conjunction<std::is_trivially_copy_constructible<data> > > >' being compiled 1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\include\xsmf_control.h(61): message : see reference to alias template instantiation 'std::_SMF_control_copy<std::_Variant_destroy_layer_<data>,data>' being compiled 1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\include\variant(462,32): error C2079: 'std::_Variant_storage_<false,data>::_Head' uses undefined struct 'data' 1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\include\variant(810): message : see reference to class template instantiation 'std::_Variant_storage_<false,data>' being compiled 1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\include\variant(916): message : see reference to class template instantiation 'std::_Variant_base<data>' being compiled 1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\include\xsmf_control.h(82): message : see reference to class template instantiation 'std::_Variant_destroy_layer_<data>' being compiled 1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\include\xsmf_control.h(120): message : see reference to class template instantiation 'std::_Deleted_copy_assign<std::_Variant_destroy_layer_<data>,data>' being compiled 1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\include\variant(1006): message : see reference to class template instantiation 'std::_Deleted_move_assign<std::_Variant_destroy_layer_<data>,data>' being compiled 1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\include\variant(1008,86): error C2139: 'data': an undefined class is not allowed as an argument to compiler intrinsic type trait '__is_destructible' 1>C:\Temp\test2019\main.cpp(4): message : see declaration of 'data' 1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\include\variant(1008): message : see reference to variable template 'const bool conjunction_v<std::is_object<data>,std::negation<std::is_array<data> >,std::is_destructible<data> >' being compiled 1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\include\variant(1008,19): error C2338: variant<Types...> requires all of the Types to meet the Cpp17Destructible requirements N4828 [variant.variant]/2.
原因分析
- 变量
a编译正常:std::variant<data>*是指针类型,C++允许用不完整类型(仅前向声明)声明指向它的指针,因为指针大小固定,编译器不需要知道data的具体结构就能处理该指针类型。 - 变量
b编译正常:std::vector<data*>存储的是data类型的指针,vector的核心操作(如内存分配、指针存储)仅依赖指针本身,不需要data的完整定义,前向声明足够。 - 变量
c编译失败:要实例化std::vector<std::variant<data>*>,编译器必须先实例化std::variant<data>模板。而MSVC的std::variant实现会在实例化阶段检查模板参数的类型特性(如是否可平凡析构、是否可析构等),这些内置类型特性要求参数必须是完整类型。但data仅为前向声明,属于不完整类型,无法满足检查要求,因此触发编译错误。从错误信息可看出,编译器处理variant的销毁层、存储层逻辑时,需要访问data的构造、析构特性,而这些都依赖data的完整定义。
解决办法
1. 提供data的完整定义
在使用std::variant<data>之前,包含定义data的头文件,让编译器获取data的完整结构。这是最直接的方案,也符合C++17标准对std::variant的要求(标准明确规定variant的所有模板参数必须是可析构的完整类型)。
2. 用封装类延迟variant实例化
如果无法提前获取data的完整定义,可以引入中间封装类,通过前向声明延迟std::variant<data>的实例化:
#include <vector> struct VariantData; // 前向声明 std::vector<VariantData*> c; // 在data完整定义的文件中实现VariantData #include "data.h" #include <variant> struct VariantData { std::variant<data>* var_ptr; // 按需添加构造、析构等逻辑 };
这种方式将variant的实例化推迟到data完整定义之后,避免编译时的类型检查错误。
内容的提问来源于stack exchange,提问作者Stéphane Chazel
相关产品推荐
相关产品推荐

