使用std::reference_wrapper绑定属性为Boost图添加边编译失败
Boost邻接表添加边触发顶点属性默认构造错误
问题背景
定义了带有自定义顶点属性的Boost邻接表:
using KinematicGraph = boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS, Model::SimulationObjects::map<std::reference_wrapper>::as<std::variant>>;
尝试通过add_edge添加边:
auto from = reinterpret_cast<const void *>(std::addressof(mapping.from())); auto to = reinterpret_cast<const void *>(std::addressof(mapping.to())); boost::add_edge(vertexMap[from], vertexMap[to], m_simulationObjectsGraph);
其中vertexMap是std::unordered_map<const void *, KinematicGraph::vertex_descriptor>,用于记录已添加顶点的描述符。
编译错误
[build] In file included from /home/dev/.conan2/p/b/boosta593711c2d7a0/p/include/boost/graph/adjacency_list.hpp:255: [build] /home/dev/.conan2/p/b/boosta593711c2d7a0/p/include/boost/graph/detail/adjacency_list.hpp:2453:17: error: call to implicitly-deleted default constructor of 'std::variant<std::reference_wrapper<mandos::SimulationObject<mandos::Particle3DTag>>>' [build] 2453 | bidir_rand_stored_vertex() {}
移除add_edge代码后编译正常,但不清楚为何会触发顶点属性的默认构造——明明没有主动创建新顶点。
原因分析
问题出在vecS顶点容器的行为上:
- 当使用
vecS作为顶点存储容器时,顶点描述符是整数类型(从0开始递增)。 - 若调用
add_edge时传入的顶点描述符大于等于当前图的顶点数量,Boost会自动创建所有缺失的顶点以补全到该描述符对应的索引。 - 你的顶点属性是包含
std::reference_wrapper的std::variant,而std::reference_wrapper没有默认构造函数,导致整个variant类型也无法默认构造,因此编译报错。
解决方案
方案1:确保顶点描述符有效
严格保证vertexMap中存储的所有顶点描述符,都是已经通过add_vertex显式添加到图中的有效描述符,避免出现描述符超出当前顶点数的情况。
方案2:更换顶点容器类型
将顶点容器从vecS改为listS(或其他非连续存储的容器):
using KinematicGraph = boost::adjacency_list<boost::vecS, boost::listS, // 更换为listS boost::bidirectionalS, Model::SimulationObjects::map<std::reference_wrapper>::as<std::variant>>;
listS的顶点描述符不是整数索引,无法自动创建顶点,必须显式调用add_vertex添加后才能使用,从根源避免自动创建顶点触发默认构造的问题。
方案3:调整顶点属性类型
修改顶点属性的variant类型,使其支持默认构造。例如给variant添加一个可默认构造的备选类型(如std::monostate):
// 假设可以调整map的模板参数,添加std::monostate Model::SimulationObjects::map<std::reference_wrapper, std::monostate>::as<std::variant>
这样variant可以默认构造为std::monostate,满足Boost内部的构造需求。
内容的提问来源于stack exchange,提问作者jjcasmar
相关产品推荐
相关产品推荐

