为何无法显式调用构造函数?如何避免隐式拷贝构造初始化成员
显式拷贝构造函数初始化类成员与std::array的解决方案
问题描述
在创建构造函数初始化封装的std::array时遇到以下问题:
- 自定义可拷贝类型
A的拷贝构造函数被声明为explicit,导致无法通过隐式调用来初始化类成员。 - 简单场景:类
B的对象无法使用默认生成的构造函数初始化其A类型成员,因为会触发隐式调用A的显式拷贝构造函数,进而编译报错。 - 复杂场景:封装
std::array的类C在初始化数组元素时,需要避免隐式调用A的拷贝构造函数。
问题代码
#include <cstddef> // std::size_t #include <utility> // std::forward #include <array> // std::array struct A { explicit A() = default; explicit A(A&) = default; // 错误:初始化'b'时被隐式调用 }; struct B { //explicit B(A& a) : a_{a} {} // 部分解决问题,但无法默认生成 A a_; }; template<class T, std::size_t N> struct C { template<class... Ts> explicit C(Ts&&... il) : values_{std::forward<Ts>(il)...} {} // 如何使用'explicit A(A&)'? std::array<T, N> values_; }; int main() { A a; B b{a}; // 基础问题 C<A, 3> c{a, a, a}; // 扩展问题 return 0; }
解决方案
1. 解决类B的初始化问题
由于A的拷贝构造函数是explicit,默认生成的B构造函数会尝试隐式调用它,导致编译错误。我们需要显式定义B的构造函数,并在初始化列表中显式调用A的拷贝构造函数:
struct B { explicit B(A& a) : a_(A(a)) {} // 显式触发A的拷贝构造 A a_; };
注:此场景下无法依赖默认生成的构造函数,必须手动定义构造函数完成显式初始化。
2. 解决类C的std::array初始化问题
std::array属于聚合类型,其初始化逻辑会尝试隐式构造每个元素。要避免隐式调用A的拷贝构造,需要在初始化数组时显式构造每个元素:
template<class T, std::size_t N> struct C { template<class... Ts> explicit C(Ts&&... il) : values_{T(std::forward<Ts>(il))...} {} // 显式调用T的构造函数,此处T为A,会触发explicit A(A&) std::array<T, N> values_; };
通过这种方式,每个数组元素都会通过显式构造完成初始化,完全符合A的拷贝构造函数的explicit约束。
额外说明
- 当前
A的拷贝构造函数参数为A&(非const),仅支持传递非const的左值对象。如果需要支持const对象的拷贝,需补充声明explicit A(const A&) = default;。 - 上述方案在C++11及以上版本均可正常运行。
内容的提问来源于stack exchange,提问作者ValeriyKarasikov
相关产品推荐
相关产品推荐

