Vector works properly
Header
std::vector<std::shared_ptr<SceneNode>> subnodes_m;
Definition
void CompositeSceneNode::AddChild(SceneNode* subnode_p)
{
subnodes_m.emplace_back(subnode_p);
}
Multimap doesn't
Header
std::multimap<unsigned int, std::shared_ptr<SceneNode>> subnodes_m;
Definition
void CompositeSceneNode::AddChild(SceneNode* subnode_p, unsigned int layerIndex)
{
subnodes_m.emplace(layerIndex, subnode_p);
}
I get following error:
error C2664: 'std::pair<_Ty1,_Ty2>::pair(const unsigned int &,const _Ty2 &)' :
cannot convert parameter 2 from 'RendererD3DWrapper::SceneNode *'
to 'const std::shared_ptr<_Ty> &'
Anybody has a clue?
You can't construct a std::pair<T1,T2>
with arguments of types U
and V
if there is no implicit conversion of U
into T1
, and V
into T2
. In your case, there is no implicit conversion of SceneNode*
into std::shared_ptr<SceneNode>
.
From the C++ standard:
§ 20.3.2 Class template
pair
[pairs.pair]
template<class U, class V> constexpr pair(U&& x, V&& y);
Requires:
is_constructible<first_type, U&&>::value
istrue
andis_constructible<second_type, V&&>::value
istrue
.Effects: The constructor initializes
first
withstd::forward<U>(x)
andsecond
withstd::forward<V>(y)
.Remarks: If
U
is not implicitly convertible tofirst_type
orV
is not implicitly convertible tosecond_type
this constructor shall not participate in overload resolution.
Having said that, you can't initialize a std::pair<T1,T2>
like below (as emplace
builds in-place a std::pair<key_type, mapped_type>
known as value_type
of std::multimap
):
std::pair<unsigned int, std::shared_ptr<SceneNode>> p( 1, new SceneNode );
because the constructor of std::shared_ptr<T>
taking a raw pointer (declared below) is an explicit
constructor, hence the error you encounter:
§ 20.9.2.2 Class template
shared_ptr
[util.smartptr.shared]
[...] template<class Y> explicit shared_ptr(Y* p);
In C++11 you should either build a std::shared_ptr<T>
before calling emplace
:
subnodes_m.emplace(layerIndex, std::shared_ptr<SceneNode>(subnode_p));
, or you can forward arguments to the constructors of pair's elements (rather than forwarding them to the constructor of std::pair<T1,T2>
itself), with a piecewise construction:
subnodes_m.emplace(std::piecewise_construct
, std::forward_as_tuple(layerIndex)
, std::forward_as_tuple(subnode_p));
Why does it work with
std::vector
ofstd::shared_ptr
's then?
The std::vector<std::shared_ptr<T>>::emplace_back
member function forwards the arguments of emplace_back
to the constructor of std::shared_ptr<T>
, satisfying the explicit context requirement. In case of a map
and a multimap
, the emplaced type is a pair
which has the constructor that forwards arguments further into its elements disabled if the conversion between argument's and parameter's types of those elements is not implicit (as cited above).