为何std::vector::emplace_back无法隐式构造OneOrMoreIntHelper对象?
问题:std::vector::emplace_back({0,0})编译失败,无需显式构造Helper类的解决办法
我定义了OneOrMoreIntHelper类,用来让Class通过单个构造函数支持单个整数或整数初始化列表的构造方式,直接构造Class对象时一切正常,但调用std::vector::emplace_back({0,0})时编译报错。目前已经有显式构造OneOrMoreIntHelper的临时解决办法,但希望能不用显式构造该对象完成操作。
代码示例
#include <initializer_list> #include <vector> struct OneOrMoreIntHelper { OneOrMoreIntHelper(const int value) {} OneOrMoreIntHelper(const std::initializer_list<int> &) {} }; struct Class { Class(OneOrMoreIntHelper) {} }; void foo() { Class single_int(0); Class list_two_ints({0, 0}); std::vector<Class> instances; // 正常运行 instances.emplace_back(0); // 编译错误:no matching function for call to ‘std::vector::emplace_back()’ instances.emplace_back({0, 0}); // 临时解决方案 instances.push_back(OneOrMoreIntHelper{0, 0}); }
编译错误信息
main.cpp: In function ‘void foo()’: main.cpp:22:27: error: no matching function for call to ‘std::vector::emplace_back()’ 22 | instances.emplace_back({0, 0}); | ~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~ In file included from /usr/include/c++/11/vector:72, from main.cpp:2: /usr/include/c++/11/bits/vector.tcc:109:7: note: candidate: ‘std::vector<_Tp, _Alloc>::reference std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {}; _Tp = Class; _Alloc = std::allocator; std::vector<_Tp, _Alloc>::reference = Class&]’ 109 | vector<_Tp, _Alloc>:: | ^~~~~~~~~~~~~~~~~~~ /usr/include/c++/11/bits/vector.tcc:109:7: note: candidate expects 0 arguments, 1 provided
问题原因
std::vector::emplace_back是一个可变参数模板函数,它需要推导传入参数的类型来匹配对应的构造函数。但初始化列表{0,0}本身不属于任何具体类型,编译器无法自动推导它应该对应std::initializer_list<int>,进而无法匹配到OneOrMoreIntHelper的构造函数,最终导致模板推导失败,报错找不到合适的函数重载。
而emplace_back(0)能正常运行,是因为0是明确的int类型,编译器可以直接推导参数类型,然后隐式调用OneOrMoreIntHelper(int)构造函数来构造Class对象。
解决方案
方案1:给初始化列表指定明确类型
将{0,0}包装成std::initializer_list<int>,让编译器能正确推导参数类型:
instances.emplace_back(std::initializer_list<int>{0, 0});
方案2:显式指定emplace_back的模板参数
直接告诉emplace_back要构造的参数类型是OneOrMoreIntHelper,这样编译器会用{0,0}来构造该类型对象:
instances.emplace_back<OneOrMoreIntHelper>({0, 0});
这两种方案都不需要显式构造OneOrMoreIntHelper临时对象,同时解决了编译错误,符合需求。
内容的提问来源于stack exchange,提问作者bers
相关产品推荐
相关产品推荐

