如何避免模板运算符重载隐式参数转换及安全实现Vec类列表初始化?
搞定继承std::array时的初始化坑
嘿,我来分享下这个问题的解决思路,刚好踩过类似的坑~
首先复盘下问题:
- 我本来是想让自己写的
Vec2(继承自std::array<float, 2>)支持Vec2 a = {1.f, 2.f}这种清爽的初始化写法 - 之前没贴出引发问题的构造函数,导致一直没找到根源,多亏Cheersandhth.-Alf提醒,补充构造函数后才发现:我写的转发构造函数会把
float这类类型错误转发给std::array的构造函数,触发了意外行为
想清楚问题根源后,我的解决方案很直接:
- 果断弃用那个风险很高的转发构造函数!毕竟它会干扰
std::array原本的聚合初始化逻辑,得不偿失 - 如果确实需要给
Vec2加一些自定义的构造逻辑,我打算这么做:- 要么只显式定义我真正需要的构造函数,比如只写接受两个
float的版本:
不过要注意:一旦定义了用户声明的构造函数,struct Vec2 : std::array<float, 2> { Vec2(float x, float y) : std::array<float, 2>{x, y} {} // 其他自定义方法... };Vec2就不再是聚合类型了,没法用{1.f, 2.f}直接初始化,得改成Vec2 a(1.f, 2.f)或者Vec2 a = Vec2{1.f, 2.f} - 如果不想放弃
{1.f, 2.f}的写法,那最简单的就是完全不定义任何自定义构造函数,让Vec2纯继承std::array的聚合特性,这样初始化写法和原生std::array完全一致,还不会有奇怪的冲突
- 要么只显式定义我真正需要的构造函数,比如只写接受两个
另外提个小细节:std::array本身是聚合类型,子类如果想保持聚合特性,就不能有任何用户声明的构造函数、私有/保护的非静态数据成员等,所以转发构造函数这种东西真的不适合加在这里~
内容的提问来源于stack exchange,提问作者eike
相关产品推荐
相关产品推荐

