如何在C++中实现带参数传递的编译时游戏引擎插件系统?
编译时插件系统支持多参数构造的实现方案
现有游戏引擎编译时插件系统仅支持向插件传递EngineT&类型参数,需扩展为支持每个插件携带自定义额外参数,通过tuple转发参数至对应插件的构造函数。
核心思路
通过辅助函数转发参数+C++17 std::apply简化元组展开,实现将engine引用与插件自定义参数一起传递给插件构造函数,同时保留原有无额外参数的兼容逻辑。
修改后的完整代码
#include <tuple> #include <string> #include <utility> // 用于std::apply、std::forward namespace engine { struct base_plugin { template<typename EngineT> base_plugin(EngineT& engine) {} ~base_plugin() = default; }; // 辅助函数:将engine引用与元组参数转发给插件构造函数 template<typename PluginT, typename EngineT, typename Tuple> PluginT construct_plugin(EngineT& engine, Tuple&& args_tuple) { return std::apply( [&engine](auto&&... args) { return PluginT(engine, std::forward<decltype(args)>(args)...); }, std::forward<Tuple>(args_tuple) ); } // 重载:无额外参数时直接用engine引用构造插件 template<typename PluginT, typename EngineT> PluginT construct_plugin(EngineT& engine) { return PluginT(engine); } template<typename... PluginTs> struct engine { std::tuple<PluginTs...> plugins; // 默认构造:兼容原有逻辑,所有插件仅接收engine引用 engine() : plugins(construct_plugin<PluginTs>(*this)...) {} // 模板构造:接受每个插件对应的额外参数元组 template<typename... ArgsTuples> explicit engine(ArgsTuples&&... args_tuples) : plugins(construct_plugin<PluginTs>(*this, std::forward<ArgsTuples>(args_tuples))...) {} }; } // 示例:带额外参数的插件 struct plugin_with_int { template<typename EngineT> plugin_with_int(EngineT& engine, int config_value) {} }; struct plugin_with_string { template<typename EngineT> plugin_with_string(EngineT& engine, const std::string& plugin_name) {} }; int main() { // 原有用法:无需额外参数 engine::engine<engine::base_plugin> basic_engine; // 新用法:为不同插件传递自定义参数 engine::engine<engine::base_plugin, plugin_with_int, plugin_with_string> extended_engine( std::tuple<>(), // base_plugin无额外参数,传空元组 std::make_tuple(42), // plugin_with_int接收int参数 std::make_tuple("Audio") // plugin_with_string接收字符串参数 ); return 0; }
关键细节说明
- 辅助函数
construct_plugin:利用std::apply将元组中的参数逐个展开,配合lambda捕获engine引用,将两者一起传递给插件的构造函数,完美转发参数的左值/右值属性。 - 双构造函数设计:默认构造函数兼容原有代码,模板构造函数支持自定义参数,确保向后兼容。
- 参数对应关系:构造函数的参数元组数量必须与模板参数中插件的数量完全匹配,无额外参数的插件传递
std::tuple<>即可。
C++20+简化版
如果使用C++20及以上,可以直接用std::make_from_tuple结合折叠表达式进一步简化,去掉辅助函数:
template<typename... PluginTs> struct engine { std::tuple<PluginTs...> plugins; engine() : plugins(PluginTs(*this)...) {} template<typename... ArgsTuples> explicit engine(ArgsTuples&&... args_tuples) : plugins( std::make_from_tuple<PluginTs>( std::tuple_cat(std::forward_as_tuple(*this), std::forward<ArgsTuples>(args_tuples)) )... ) {} };
这里通过std::tuple_cat将engine引用的tuple与插件参数tuple合并,再用std::make_from_tuple直接构造插件实例,代码更紧凑。
内容的提问来源于stack exchange,提问作者Alexandre Deus
相关产品推荐
相关产品推荐

