使用C++可变参数模板替代默认参数是否合理?
用C++可变参数模板实现灵活初始化的合理性探讨
原场景与现有实现
我想通过C++可变参数模板实现结构体的灵活初始化,但这个模式不算常见,不确定有没有隐藏问题,先把场景和方案列出来,请大家帮忙判断合理性:
现有一个带默认参数的结构体构造函数:
struct foo { foo(int a = 1, double b = 2.0) : _a(a), _b(b) {} private: int _a; double _b; };
现有实现的痛点
这个实现存在两个明显问题:
- 如果只想指定
b的值,必须同时指定a;要解决这个问题只能新增foo(double)构造函数重载 - 要是后续新增成员(比如
float c),用户想指定新成员时必须同时传a、b的值;对应的解决方案需要新增大量构造函数重载,数量随参数数量增长呈阶乘级上升
我的可变参数模板解决方案
我想到的解决办法是用可变参数模板,实现如下:
struct foo { template<typename... Args> foo(Args&&... args) : _a(1), _b(2.0) { setup(std::forward<Args>(args)...); } private: template<typename... Args> void setup(int a, Args&&... args) { _a = a; setup(std::forward<Args>(args)...); } template<typename... Args> void setup(double b, Args&&... args) { _b = b; setup(std::forward<Args>(args)...); } void setup() {} int _a; double _b ; };
这个方案看起来复杂,但实际有几个优势:
- 新增成员时只需要添加对应的
setup()重载即可,无需写大量构造函数 - 参数顺序可以任意调整
- 保持原有API的兼容性
方案的已知缺点
不过我也发现了两个缺点:
- 每个参数的类型必须唯一,不过这反而能促使我们使用更具语义的特定类型(比如用
Speed替代double) - 成员会被初始化两次:一次在构造函数初始化列表,一次在
setup()函数中
疑问
我只在已废弃的boost::process::v1中见过类似模式,而boost::process::v2的文档提到v1的参数方式扩展性不佳,改用了更清晰的组件化初始化方式,不确定这点会不会影响我的设计。
内容的提问来源于stack exchange,提问作者Stewart
相关产品推荐
相关产品推荐

