仅用类型参数的可变参数模板提取类静态成员是否可行?
当然可行!而且你的核心思路完全正确
你的需求是无需实例化类就能获取一组类的同名静态成员,这在C++里是完全可以实现的——因为静态成员属于类本身,不是对象实例的一部分,所以只要能拿到类的类型(比如通过模板参数传入),直接用类名::静态成员就能访问,根本不需要创建类的对象。
先分析你提供的代码
首先把你的代码格式化一下:
#include <iostream> class a { public: a() : i(2) {} template <typename ...ts> void exec() { f<ts...>(); std::cout << "a::exec()" << std::endl; } int i; private: template <typename t> void f() { i += t::i; } template <typename t, typename ...ts> void f() { f<t>(); f<t, ts...>(); // 这里有bug!会导致无限递归 } }; struct b { static const int i = -9; }; struct c { static const int i = 4; }; int main() { a _a; _a.exec<b,c>(); std::cout << _a.i << std::endl; }
代码里的问题
你的核心逻辑没问题,但递归的f函数写反了:第二个模板重载里,应该调用f<ts...>()而不是f<t, ts...>()——后者会无限重复调用f<b,c>(),永远触发不了单参数的终止版本,运行时会直接栈溢出崩溃。
修正后的代码
把递归调用改成f<ts...>(),就能正确遍历所有传入的类类型,累加每个类的静态i:
#include <iostream> class a { public: a() : i(2) {} template <typename ...ts> void exec() { f<ts...>(); std::cout << "a::exec()" << std::endl; } int i; private: template <typename t> void f() { i += t::i; } template <typename t, typename ...ts> void f() { f<t>(); f<ts...>(); // 修正这里,递归处理剩余的模板参数 } }; struct b { static const int i = -9; }; struct c { static const int i = 4; }; int main() { a _a; _a.exec<b,c>(); std::cout << _a.i << std::endl; // 输出:2 + (-9) +4 = -3 }
更简洁的现代C++实现
如果你用C++17及以上,可以用折叠表达式替代递归模板,代码更简洁易读,不需要写递归的重载:
#include <iostream> class a { public: a() : i(2) {} template <typename ...ts> void exec() { // 折叠表达式:依次对每个ts调用f<ts>() (f<ts>(), ...); std::cout << "a::exec()" << std::endl; } int i; private: // 只需要单参数的f模板即可 template <typename t> void f() { i += t::i; } }; struct b { static const int i = -9; }; struct c { static const int i = 4; }; int main() { a _a; _a.exec<b,c>(); std::cout << _a.i << std::endl; // 同样输出-3 }
关键结论
- 你的需求完全可以实现,而且你的核心思路(用模板参数传递类类型,直接访问静态成员)是正确的,全程不需要实例化
b、c这些类。 - 静态成员的本质就是属于类的全局变量,只要能拿到类的类型,不管是通过模板参数、
decltype还是其他方式,都能直接访问,不需要创建对象。
内容的提问来源于stack exchange,提问作者canellas
相关产品推荐
相关产品推荐

