I have a pair of function templates defined like so:
template<typename CollectionType>
Foo<CollectionType> f(const CollectionType& v)
{
return Foo<CollectionType>(v); // copies v into a member variable
}
template<typename CollectionType>
Foo<CollectionType> f(CollectionType&& v)
{
return Foo<CollectionType>(std::move(v)); // moves v into a member variable
}
If I call f
as below:
std::vector<int> v;
f(v);
The VC++ compiler favors the &&
overload, apparently because it is less specialized. I would like the const&
overload to be called in this case--the &&
version is intended for constructions like f(ReturnAVector())
. Is there a way to achieve this without manually specifying the template argument?
After a fair amount of effort, I came up with this:
template<typename CollectionType>
Foo<CollectionType> f(const CollectionType& v)
{
return Foo<CollectionType>(v); // copies v into a member variable
}
template<typename CollectionType>
typename std::enable_if<std::is_rvalue_reference<CollectionType&&>::value,
Foo<typename std::remove_reference<CollectionType>::type>>::type
f(CollectionType&& v)
{
return Foo<CollectionType>(std::move(v)); // moves v into a member variable
}
But wow; is that really the simplest way to get what I'm after?
With:
you call
f(std::vector<int>&)
sois an exact match (universal reference)
CollectionType
isstd::vector<int>&
whereasrequires a const promotion.
A possible solution is to add a version non const:
or to forward your argument, something like:
The second overload is always an exact match. So there is in fact no need for the first overload and it can only cause ambiguity. Instead of moving, you should forward the argument.
Scott Meyers has given an excellent explanation of this: http://scottmeyers.blogspot.nl/2012/11/universal-references-in-c11-now-online.html