C++17中能否使用变量类型初始化模板类?
你想要通过遍历类型列表替代繁琐的条件判断来创建子类实例的思路是可行的,但你期望的for (S subclass_type : {A, B, C})写法无法直接实现——因为类型是编译期概念,不能作为运行时对象放进初始化列表中遍历。不过借助C++17的模板元编程特性,我们可以实现类似的简化效果,以下是几种常用方案:
原繁琐代码
class S {}; class A : public S {}; class B : public S {}; class C : public S {}; for (int i = 0; i < 3; i++) { std::shared_ptr<S> p; if (i == 0) { p = std::make_shared<A>(); } else if (i == 1) { p = std::make_shared<B>(); } else if (i == 2) { p = std::make_shared<C>(); } // Do something with 'p' }
方案一:模板参数包+折叠表达式(编译期遍历)
利用C++17的折叠表达式,直接将类型列表作为模板参数传入,编译期自动展开为逐个处理逻辑:
#include <memory> class S {}; class A : public S {}; class B : public S {}; class C : public S {}; template<typename... Subclasses> void process_subclasses() { // 对每个子类类型执行创建和处理逻辑 ( [&]() { std::shared_ptr<S> p = std::make_shared<Subclasses>(); // 这里编写处理p的业务代码 }(), ... ); } int main() { // 传入要处理的子类类型列表 process_subclasses<A, B, C>(); return 0; }
方案二:结合std::tuple与std::apply(编译期遍历)
如果需要更贴近“容器遍历”的写法,可以用std::tuple存储类型,再通过std::apply展开处理:
#include <memory> #include <tuple> #include <utility> class S {}; class A : public S {}; class B : public S {}; class C : public S {}; template<typename... Subclasses> void process_subclasses() { // 用tuple包装类型列表 auto type_tuple = std::make_tuple<Subclasses...>(); std::apply([&](auto&&... args) { ( [&]() { // 从tuple元素推导子类类型 using Subclass = std::decay_t<decltype(args)>; std::shared_ptr<S> p = std::make_shared<Subclass>(); // 处理p的业务代码 }(), ... ); }, type_tuple); } int main() { process_subclasses<A, B, C>(); return 0; }
方案三:工厂函数数组(运行时遍历)
如果需要根据运行时变量(比如索引、用户输入)动态选择类型,可以预先定义工厂函数数组,通过遍历数组调用创建逻辑:
#include <memory> #include <vector> class S {}; class A : public S {}; class B : public S {}; class C : public S {}; int main() { // 构建工厂函数列表,每个函数对应一个子类的创建逻辑 std::vector<std::shared_ptr<S>(*)()> factories = { []() { return std::make_shared<A>(); }, []() { return std::make_shared<B>(); }, []() { return std::make_shared<C>(); } }; // 遍历工厂函数创建实例 for (auto& factory : factories) { std::shared_ptr<S> p = factory(); // 处理p的业务代码 } return 0; }
以上三种方案都能有效替代原有的if-else判断逻辑,方案一、二是编译期处理,性能更优;方案三支持运行时动态选择,灵活性更强,可根据实际需求选择。
内容的提问来源于stack exchange,提问作者Mossmyr
相关产品推荐
相关产品推荐

