Reputation: 11424
I have an std::multimap of the following type:
typedef std::multimap<std::pair<bool,uint32_t>, FooObject>
The FooObject has default move copy and assign constructors declared:
FooObject(FooObject&& v) = default;
FooObject& operator=(FooObject&& other)=default;
The copy/assign constructors are private to disable implicit copy.
So I should be able to emplace a pair into the map like this:
mymap.emplace(std::make_pair(false,32),FooObject());
This throws a list of errors with the one at the end:
error C2660: 'std::pair::pair': function does not take 2 arguments
If I declare move copy assign constructors without "default" then it compiles ok.
FooObject(FooObject&& v){}
FooObject& operator=(FooObject&& other){}
Why is that? Does the compiler optimize away these constructors when marked with "default" keyword? I am using MSVC140
UPDATE:
Based on the comments below I found the reason - FooObject has a non-copiable member instance. Here is the FooObject:
#define NO_COPY_ASSIGN(TypeName) \
TypeName (const TypeName &); \
void operator= (const TypeName &);
class FooObject
{
private:
NO_COPY_ASSIGN(FooObject)
public:
struct FooStruct
{
FooBuffer frameBuffer; //<--Here it is
}fooStruct;
FooObject(){}
/** Move constructor to allow insert into vector without copy */
FooObject(FooObject&& v) = default;
FooObject& operator=(FooObject&& other) = default;
};
*FooBuffer has also its copy/assign private.But I still don't get why replacing 'default' with {} fixes that.Please explain.
Upvotes: 3
Views: 245
Reputation: 180435
The difference between
FooObject(FooObject&& v) = default;
and
FooObject(FooObject&& v){}
Is that the former will emit a constructor that moves each member from v
while the latter default constructs each member and does nothing with v
.
Since FooBuffer
is not movable that means that the compiler will delete FooObject(FooObject&& v) = default;
as it would be ill-formed.
With FooObject(FooObject&& v){}
you do not have that problem as you never try to move the members of v
. Since there is no member initialization list the compiler will add one for you that just default constructs the members.
You can see this behavior more explicitly with this:
struct Moveable
{
Moveable() = default;
Moveable(Moveable&&) { std::cout << "in Moveable(Moveable&&)\n"; }
};
struct Foo
{
Foo() = default;
Foo(Foo&&) = default;
Moveable m;
};
struct Bar
{
Bar() = default;
Bar(Bar&&){}
Moveable m;
};
int main()
{
Foo f;
Bar b;
std::cout << "test_f\n";
Foo test_f(std::move(f));
std::cout << "test_b\n";
Bar test_b(std::move(b));
}
which outputs
test_f
in Moveable(Moveable&&)
test_b
Showing that nothing is actually moved in Bar
's move constructor.
Upvotes: 1
Reputation: 96233
Your problem is that one of the member of FooObject
is not move-able, which prevents the compiler from generating default move operations.
The {}
versions of the move operations you implement yourself do no work (specifically: they don't actually do a move operation) on the members of FooObject
and are thus legal.
Upvotes: 2