map::emplace() with a custom value type
Asked Answered
C

2

23

I'm having trouble using map::emplace(). Can anyone help me figure out the right syntax to use? I am effectively trying to do the same thing as in this example. Here is my version:

#include <map>
using namespace std;

class Foo
{
  // private members

  public:
    Foo(int, char, char) /* :init(), members() */ {  }

    // no default ctor, copy ctor, move ctor, or assignment
    Foo() = delete;
    Foo(const Foo&) = delete;
    Foo(Foo &&) = delete;
    Foo & operator=(const Foo &) = delete;
    Foo & operator=(Foo &&) = delete;
};


int main()
{
  map<int, Foo> mymap;
  mymap.emplace(5, 5, 'a', 'b');

  return 0;
}

Under GCC 4.7 (with the -std=c++11 flag), I am erroring out on the emplace line. The example I linked above doesn't say anything about how to deal with custom types instead of primitives.

Calondra answered 28/12, 2012 at 20:6 Comment(1)
See also #13689982Incestuous
T
26

A container's emplace member constructs an element using the supplied arguments.

The value_type of your map is std::pair<const int, Foo> and that type has no constructor taking the arguments { 5, 5, 'a', 'b' } i.e. this wouldn't work:

std::pair<const int, Foo> value{ 5, 5, 'a', 'b' };
map.emplace(value);

You need to call emplace with arguments that match one of pair's constructors.

With a conforming C++11 implementation you can use:

mymap.emplace(std::piecewise_construct, std::make_tuple(5), std::make_tuple(5, 'a', 'b'));

but GCC 4.7 doesn't support that syntax either (GCC 4.8 will when it's released.)

Tobit answered 28/12, 2012 at 20:48 Comment(3)
This seems to work fine, even on GCC 4.7. Thanks. FWIW, I used std::forward_as_tuple() instead of std::make_tuple(), because I think it should be slightly better optimized, but I'm not really sure what the difference is.Calondra
forward_as_tuple(5, 'a', 'b') creates tuple<int&&, char&&, char&&> and make_tuple(5, 'a', 'b') creates tuple<int, char, char>. In general forward_as_tuple avoids making copies of its arguments and forwards references, but in this case (with int and char arguments) the copies created by make_tuple are probably cheaper than creating references. It's also less typing :)Tobit
As for C++17, map.try_emplace(5, 5,'a','b') ; can be used, too.Maracanda
M
3

GCC 4.7 does not have full support of emplace functions.

You can see C++11 support in GCC 4.7.2 here.

Machree answered 28/12, 2012 at 20:7 Comment(7)
I was afraid of that. Is what I tried the correct syntax though? Ie, would it work on some other compiler?Calondra
Also, emplace() works fine with map<char, int> like in the cplusplus.com example.Calondra
@SchighSchagh You might need to forward_as_tuple, I'm not sure as I have never used emplace.Machree
It is a valid reason that the call would not work. The fact that you have another is not justification for downvote.Endanger
@SchighSchagh: the cplusplus example doesn't work on g++-4.7.2 also, I just tested it.Dx
The linked document is out of date, GCC trunk (which that page refers to) does support map::emplace, the correct link for GCC 4.7 is gcc.gnu.org/onlinedocs/gcc-4.7.2/libstdc++/manual/manual/…Tobit
@JonathanWakely good to know. The link I gave was a bookmark I had.Machree

© 2022 - 2024 — McMap. All rights reserved.