You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何无法显式调用构造函数?如何避免隐式拷贝构造初始化成员

显式拷贝构造函数初始化类成员与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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 09:55:28