I have an issue constructing my non-copyable object . Let consider the following example :
class Uncopyable{
protected:
Uncopyable(){};
~Uncopyable(){};
private:
Uncopyable(const Uncopyable&);
Uncopyable& operator=(const Uncopyable&);
};
class Base { };
class Derived : public Base { };
class A : private Uncopyable {
public:
A(std::map<std::string, std::shared_ptr<Base>> & inMap);
private:
A(const A&);
A& operator=(const A&);
};
int main() {
std::map<std::string, std::shared_ptr<Derived>> lMap;
std::shared_ptr<A> oA(std::make_shared<A>(lMap));
}
If I assume my object A to be non-copyable , it does not work.As a pointer, I expect my object A to understand that Derived is a Base, but instead I am getting the following message:
error C2664: 'A::A(const A &)' : cannot convert argument 1 from 'std::map<std::string,std::shared_ptr<Derived>,std::less<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>>' to 'std::map<std::string,std::shared_ptr<Base>,std::less<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>> &'
1> with
1> [
1> _Kty=std::string
1> , _Ty=std::shared_ptr<Derived>
1> ]
1> and
1> [
1> _Kty=std::string
1> , _Ty=std::shared_ptr<Base>
1> ]
Thanks.
The error has nothing to do with A
's noncopyability and indeed is not in the copy constructor - it's in the map
constructor. The error has to do with the fact that A'
constructor takes a
std::map<std::string, std::shared_ptr<Base>> &
and you are passing a:
std::map<std::string, std::shared_ptr<Derived>>
An argument that is an lvalue reference of type T
can only be satisfied by an lvalue of type T
or of a type derived from T
(or of a type with an operator T&
). But std::map<std::string, std::shared_ptr<Derived>>
does not actually inherit from std::map<std::string, std::shared_ptr<Base>>
- nor are the two types related at all - there is no cross-type constructor for std::map
.
In other words, just because a D
is a B
doesn't mean that a map<X, D>
is a map<X, B>
. There is no covariance of types in the C++ type system in this way. Some types at least allow you to construct a Class<B>
from a Class<D>
(e.g. std::shared_ptr
), but that's not true of the standard containers (e.g. vector
, map
, ...)
You will have to change lMap
to hold std::shared_ptr<Base>
s in order for this to work. It can internally hold std::shared_ptr<Derived>
s - but the map
types have to match.
Side-note, in C++11 you don't need Uncopyable
. You can simply explicitly delete
those operations:
A(A const& ) = delete;
A& operator=(A const& ) = delete;