I use a class OneOrMoreIntHelper
that accepts both a single integer as well as an initializer list of integers, and that works great to construct instances of Class
through a single constructor.
However, this fails when trying to use emplace_back
. E.g., this code example does not compile, giving the error message
no matching function for call to ‘std::vector::emplace_back()’
#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;
// this works fine
instances.emplace_back(0);
// error: no matching function for call to ‘std::vector::emplace_back()’
instances.emplace_back({0, 0});
// Workaround
instances.push_back(OneOrMoreIntHelper{0, 0});
}
I have found the workaround above, but ideally, I would like to not have to instantiate the OneOrMoreIntHelper
object at all (in the end, the whole point is to be able to type 0
instead of {0}
, so having to type OneOrMoreIntHelper{0, 0}
elsewhere complete defeats the purpose).
Complete build log:
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
The reason why instances.emplace_back({0, 0});
fails is that emplace_back
is a function template, and you cannot deduce its template parameters from an initializer-list. See also Why doesn't my template accept an initializer list. Specifically, it's not possible because this is a non-deduced context (see this answer, heading 6).
However, you can write:
instances.emplace_back(std::initializer_list<int>{0, 0});
// or
auto list = {0, 0};
instances.emplace_back(list);
This is similar to Emplacement of a vector with initializer list