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

如何让自定义构造函数实现类B那样的聚合初始化行为?

问题:自定义构造函数模拟聚合初始化的无拷贝效果

先看示例代码:

#include <iostream>

using namespace std;

struct A {
    A() { cerr << "default" << endl; }
    A(const A &a) { cerr << "copy" << endl; }
    A(A &&a) { cerr << "move" << endl; }
};

struct B {
    A a;
};

struct C {
    A a;
    C(A a): a(a) {}
};

int main() {
    B b {A()};
    cerr << "=======" << endl;
    C c {A()};
    return 0;
}

编译运行输出:

default
=======
default
copy

可见类B的聚合初始化直接就地构造成员a,无额外拷贝;而类C的自定义构造函数会先构造参数对象,再拷贝到成员。即使修改为C(A a): a(forward<A>(a)) {},也只能实现移动而非就地构造的效果。如何让自定义构造函数复刻聚合初始化的无拷贝/无移动行为?


解决方案

核心思路是让构造函数直接在成员对象的内存空间中构造实例,跳过中间参数对象的创建,这和聚合初始化的本质逻辑一致。具体可以通过模板化完美转发构造函数实现:

基础实现

struct C {
    A a;
    // 完美转发所有参数,直接在成员a的位置构造对象
    template<typename... Args>
    C(Args&&... args) : a(std::forward<Args>(args)...) {}
};

修改后运行代码,输出会和类B的情况完全一致:

default
=======
default

原理说明

聚合初始化是直接在成员的内存地址上调用构造函数;而模板转发构造函数会把传入的参数直接传递给成员a的构造函数,同样实现就地构造,不会产生中间的临时对象,自然没有拷贝或移动操作。

之前的传值构造函数(包括带forward的版本)之所以无法做到,是因为参数a是一个独立的临时对象,必须先构造它,再通过移动/拷贝赋值给成员,无法避免额外操作。

可选:添加类型约束(避免滥用)

如果想限制构造函数仅接受能合法构造A的参数,可以用SFINAE添加约束,防止意外的类型转换:

#include <type_traits>

struct C {
    A a;
    template<typename... Args, 
             // 仅当参数可构造A时启用该构造函数
             std::enable_if_t<std::is_constructible_v<A, Args...>, int> = 0>
    C(Args&&... args) : a(std::forward<Args>(args)...) {}
};

内容的提问来源于stack exchange,提问作者Nanored

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 22:48:11