C++如何在以GraphTypes为模板参数的类中访问其可变参数
错误原因分析
- C3520错误:模板参数包是一组类型的集合,不能直接赋值给单个
using类型别名,必须展开或者用模板容器(比如std::tuple)包裹。 - C3543错误:你之前定义的
ContextType不是参数包,后续代码尝试展开它自然会报错。
解决方案
通过对Edge类做模板偏特化,直接从GraphTypes的模板参数中提取出Context参数包,不需要在GraphTypes内部做复杂的类型定义,就可以直接使用参数包,同时兼容无Context的场景。
修改后完整代码
#include <initializer_list> // 首先修改GraphTypes,添加可变参数包 template<class GraphT, class NodeT, class EdgeT, class... ContextT> class GraphTypes { public: using GraphType = GraphT; using NodeType = NodeT; using EdgeType = EdgeT; }; // 前置声明Edge template<class GraphTypes> class Edge; // Edge偏特化:直接提取GraphTypes的所有模板参数,包括Context包 template<template<typename, typename, typename, typename...> class GraphTypesT, class GraphT, class NodeT, class EdgeT, class... ContextT> class Edge<GraphTypesT<GraphT, NodeT, EdgeT, ContextT...>> { private: using GraphType = GraphT; using NodeType = NodeT; using EdgeType = EdgeT; public: NodeType &GetSource(); void SetSource(NodeType &Source, ContextT&... Context); protected: NodeType *m_pSource = nullptr; }; // GetSource实现 template<template<typename, typename, typename, typename...> class GraphTypesT, class GraphT, class NodeT, class EdgeT, class... ContextT> inline NodeType &Edge<GraphTypesT<GraphT, NodeT, EdgeT, ContextT...>>::GetSource() { return *m_pSource; } // SetSource实现 template<template<typename, typename, typename, typename...> class GraphTypesT, class GraphT, class NodeT, class EdgeT, class... ContextT> void Edge<GraphTypesT<GraphT, NodeT, EdgeT, ContextT...>>::SetSource(NodeType &Source, ContextT&... Context) { if(&Source == m_pSource) return; // 空参数包时展开也不会报错,C++11及以上都支持 std::initializer_list<bool>{ (Context.PreSetSource(*this), true)... }; m_pSource = &Source; std::initializer_list<bool>{ (Context.PostSetSource(*this), true)... }; }
使用示例
无上下文场景
class MyGraph; class MyNode; class MyEdge; // 不需要Context时直接传三个参数即可 using MyGraphTypes = GraphTypes<MyGraph, MyNode, MyEdge>; class MyEdge : public Edge<MyGraphTypes> {}; // 调用时不需要传Context MyNode n; MyEdge e; e.SetSource(n);
带上下文场景
struct Context1 { void PreSetSource(MyEdge& e) {} void PostSetSource(MyEdge& e) {} }; struct Context2 { void PreSetSource(MyEdge& e) {} void PostSetSource(MyEdge& e) {} }; // 带两个上下文的定义 using MyGraphTypesWithCtx = GraphTypes<MyGraph, MyNode, MyEdge, Context1, Context2>; class MyEdgeWithCtx : public Edge<MyGraphTypesWithCtx> {}; // 调用时传入对应的Context对象 Context1 c1; Context2 c2; MyNode n; MyEdgeWithCtx e; e.SetSource(n, c1, c2);
内容的提问来源于stack exchange,提问作者Magnar Myrtveit
相关产品推荐
相关产品推荐

