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

C++11中如何以引用方式传递可变数量的对象?

在C++11中以引用方式传递可变数量的对象

刚好我之前也碰到过类似的困扰——C风格可变参数不仅语法丑陋,还类型不安全;而直接用std::initializer_list又会默认传值,导致对象被复制,完全达不到操作原对象的目的。不过C++11里有两种优雅的解决方案,能完美满足你的需求,我给你一步步演示:

方案1:用std::reference_wrapper包装引用

std::initializer_list本身只能存储值类型,但我们可以用<functional>里的std::reference_wrapper来包装对象引用,它是可拷贝的,刚好能放进initializer_list里。

首先补全你的MyClass定义(方便测试):

#include <iostream>
#include <initializer_list>
#include <functional> // 别忘了包含这个头文件

class MyClass {
public:
    MyClass() : m_id(0), m_idChecks(0) {}
    ~MyClass(){}
    int getId() { 
        m_idChecks++; 
        return m_id; 
    }
    int getIdChecks() const { 
        return m_idChecks; 
    }
    void setId(int id) { m_id = id; }
private:
    int m_id;
    int m_idChecks;
};

然后定义接收包装后引用的函数:

void processObjects(std::initializer_list<std::reference_wrapper<MyClass>> objects) {
    for (auto& obj_wrap : objects) {
        // 用get()获取原始的对象引用
        MyClass& obj = obj_wrap.get();
        std::cout << "当前对象ID:" << obj.getId() << std::endl;
    }
}

测试一下效果:

int main() {
    MyClass obj1, obj2, obj3;
    obj1.setId(10);
    obj2.setId(20);
    obj3.setId(30);

    // 调用时直接传对象,语法和传值的initializer_list几乎一样
    processObjects({obj1, obj2, obj3});

    // 验证原对象的计数是否正确累加
    std::cout << "obj1的getId被调用:" << obj1.getIdChecks() << "次\n";
    std::cout << "obj2的getId被调用:" << obj2.getIdChecks() << "次\n";
    std::cout << "obj3的getId被调用:" << obj3.getIdChecks() << "次\n";

    return 0;
}

运行后你会看到,三个对象的getIdChecks都只增加了1次,说明我们操作的都是原对象,没有发生复制。

方案2:使用可变模板参数(Variadic Templates)

如果不需要把这些对象放进一个集合里处理,可变模板参数会是更简洁的选择,它直接传递每个对象的引用,不需要额外包装:

// 定义一个模板函数,接收任意数量的MyClass引用
template<typename... Args>
void processObjects(Args&... objects) {
    // 用C++11的方式展开参数包(借助initializer_list)
    (void)std::initializer_list<int>{ 
        (std::cout << "当前对象ID:" << objects.getId() << std::endl, 0)... 
    };
}

调用的时候更简单,直接传对象就行,不用加大括号:

int main() {
    MyClass obj1, obj2, obj3;
    obj1.setId(10);
    obj2.setId(20);
    obj3.setId(30);

    processObjects(obj1, obj2, obj3);

    std::cout << "obj1的getId被调用:" << obj1.getIdChecks() << "次\n";
    std::cout << "obj2的getId被调用:" << obj2.getIdChecks() << "次\n";
    std::cout << "obj3的getId被调用:" << obj3.getIdChecks() << "次\n";

    return 0;
}

这个方案的语法更清爽,而且完全没有额外的开销,非常适合简单的批量处理场景。

两种方案的对比

  • std::reference_wrapper+initializer_list:适合需要将对象集合保存起来(比如放进容器)的场景,调用语法和传统initializer_list一致,容易理解。
  • 可变模板参数:调用更简洁,性能开销更小,适合直接对每个对象做相同操作的场景。

这两种方法都完美避开了C风格可变参数的缺点,也解决了initializer_list传值的问题,完全符合C++11的优雅风格~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 03:51:51