Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Why can't I use std::vector::emplace_back without explicitly constructing an intermediate object, although instance creation works without one?

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()’

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

#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

>Solution :

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

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading