如何用std::make_unique传递复杂类型作为构造函数参数?报错解析
解决std::make_unique传递初始化列表构造复杂类型的编译错误
这个问题我之前在项目里也踩过坑,咱们先搞清楚为什么会报错,再看怎么解决。
为什么make_unique<MyClass>({1,2})会报错?
std::make_unique是一个模板函数,它需要推导传入参数的具体类型才能匹配正确的重载。但C++里,像{1,2}这样的初始化列表属于「非推导上下文」——编译器没办法自动推断出它应该对应std::tuple<int, int>类型,所以就找不到接受这个参数的make_unique重载,最终报出“函数不接受1个参数”的错误。
而其他几种写法能正常工作的原因:
make_unique<MyClass>(mt):mt是明确的std::tuple<int,int>对象,类型清晰,编译器能直接推导。make_unique<MyClass>(make_tuple(1,2)):make_tuple直接返回了std::tuple<int,int>类型的对象,同样类型明确。unique_ptr<MyClass>(new MyClass({1,2})):这里是直接调用MyClass的构造函数,构造函数的参数是std::tuple<int,int>,编译器会自动把{1,2}隐式转换为tuple,所以没问题。
几种可行的解决方案
方案1:显式构造tuple对象
最直接的办法,把初始化列表包装成明确的tuple类型,让编译器能正确推导:
auto myClass1 = make_unique<MyClass>(std::tuple<int, int>{1, 2});
这种方式不需要修改MyClass的代码,适合不想改动类定义的场景。
方案2:给MyClass添加初始化列表构造函数
如果想让{1,2}的调用方式更自然,可以给MyClass加一个接受std::initializer_list<int>的构造函数:
class MyClass { private: std::tuple<int, int> mytuple; public: MyClass(std::tuple<int, int> param) : mytuple(param) {} // 新增的初始化列表构造函数 MyClass(std::initializer_list<int> init) { if (init.size() != 2) { throw std::invalid_argument("Initializer list must have exactly 2 elements"); } auto it = init.begin(); mytuple = std::make_tuple(*it, *(++it)); } };
这样你就可以直接写auto myClass1 = make_unique<MyClass>({1,2});,编译器会匹配到新增的构造函数,推导也没问题。不过要注意加个长度检查,避免传入元素数量不对的情况。
方案3:使用std::make_tuple(你已经知道的方式)
其实你已经发现了,用make_tuple(1,2)也能解决问题,本质和方案1一样,都是传递明确的tuple对象:
auto myClass01 = make_unique<MyClass>(make_tuple(1,2));
这种写法也很简洁,不需要改动类代码。
内容的提问来源于stack exchange,提问作者Dmitry
相关产品推荐
相关产品推荐

