1

Related to my previous question: Inserting an object having a non copyable field into an std::vector

It seems that I can have a map storing non-movable objects A only if A is default constructable.

Is there any way in C++11 to have a map store A if A is not default-constructable and non-movable?

#include <mutex>
#include <map>
#include <iostream>

class A {
  public:
     A(int i) {}

  private:
    std::mutex m;
};


int main() {
    std::map<int, A> m;
    //m.emplace(1, 3); //A is not movable => does wouldn't compile.
}
Community
  • 1
  • 1
user695652
  • 4,105
  • 7
  • 40
  • 58
  • `A` doesn't even need to be default-constructable, if you avoid using `operator[]`. – aschepler Oct 14 '16 at 19:14
  • 1
    `m[0]` requires `A` to be default-constructible because it is specified to default-construct a value if one does not yet exist for that key. – Tavian Barnes Oct 14 '16 at 19:15
  • You should use `m.emplace(1);` instead of `m.emplace(1, A{});`. Not sure if that second one is even valid. Anyway, the first one _actually_ inserts the element in place. – yyny Oct 14 '16 at 19:22
  • @ aschepler How would you insert A into the map without using the index operator? – user695652 Oct 14 '16 at 19:22
  • @– YoYoYonnY Thanks for your comment. I am not sure if my question is clear, but A is not movable. – user695652 Oct 14 '16 at 19:23
  • @user695652 `m.emplace(std::piecewise_construct, std::forward_as_tuple(1), std::forward_as_tuple());` – Daniel Schepler Oct 14 '16 at 19:24
  • @user695652 I'm not sure if my method is correct, looking at a reference manual the arguments to emplace will be used to construct a pair, not just an element. Daniel's method might work. – yyny Oct 14 '16 at 19:25
  • @user695652 The problem with your usage of `m.emplace(1, A{})`; is that it constructs `A` (Using `A{}`) _before_ it is inserted into the `std::map`. You would have to pass the `emplace` arguments such that it constructs `A` in-place. Daniels method might do that. – yyny Oct 14 '16 at 19:28
  • With the edited question, if I uncomment `m.emplace(1, 3);` it does compile for me. (This would fall under http://en.cppreference.com/w/cpp/utility/pair/pair case (3).) – Daniel Schepler Oct 14 '16 at 19:35
  • @DanielSchepler I get an error: use of deleted function 'A::A(const A&)' – user695652 Oct 14 '16 at 19:37
  • Yes, I'm sure, I've compiled it using gcc 6.2.0. – Daniel Schepler Oct 14 '16 at 19:39
  • I see, it's a C++14 feature, I'm using gcc 4.8.2 wiht --std=c++11 flag (can't use 14) – user695652 Oct 14 '16 at 19:40
  • Hmm... logging into an Ubuntu 14.04 machine with gcc 4.8.4, I can indeed reproduce the compiler or standard library bug. But `m.emplace(std::piecewise_construct, std::forward_as_tuple(1), std::forward_as_tuple(3))` does compile there as well to work around the bug. – Daniel Schepler Oct 14 '16 at 19:44
  • Oh, also, I think if the `A(int)` constructor were `explicit` then the `piecewise_construct` version would still be needed - the cppreference documentation says pair constructor (3) only participates in overload if the arguments are implicitly convertible to the corresponding pair elements. – Daniel Schepler Oct 14 '16 at 19:49
  • @ Daniel Schepler thanks this worked. But why are you calling this behavior a bug of gcc, std11? – user695652 Oct 14 '16 at 19:51

0 Answers0