In my current project we are building for Linux and Windows at the same time. Unfortunately because some platform issues our MSVC is very old. We are using MSVC 2010. And gcc we are using relatively new and smarter which has the version 4.8 .
The code below compile in gcc but MSCV nags about it :
template<class T, class U>
std::shared_ptr<T> Cast( const std::shared_ptr<U>& spObject ) // rename from CastTerrainObject
{
return std::dynamic_pointer_cast<T>(spObject);
}
template<class T, class U>
std::tr1::shared_ptr<T> Cast( const std::tr1::shared_ptr<U>& spObject ) // rename from CastTerrainObject
{
return std::tr1::dynamic_pointer_cast<T>(spObject);
}
MSVC began nagging after I add the second overload for std::tr1::shared_ptr. The compile errors I am getting repeatedly :
error C2995: 'std::tr1::shared_ptr<_Ty> Cast(const std::tr1::shared_ptr<_Ty2> &)' : function template has already been defined
And
error C2440: 'initializing' : cannot convert from 'std::tr1::shared_ptr<_Ty> (__cdecl *)(const std::tr1::shared_ptr<_Ty2> &)' to 'std::tr1::shared_ptr<_Ty>'
Do you guys have a solution for my case?
Make your Cast
function template take a template template parameter:
template<typename T, template<class> class SP, class U>
SP<T> Cast2(SP<U> const& sp) {
using std::dynamic_pointer_cast;
using std::tr1::dynamic_pointer_cast;
return dynamic_pointer_cast<T>(sp);
}
Leaving the original answer for posterity. It is ill-formed on VC++ (though it works as expected), because there is no valid specialization of the function.
Disable the second overload if std::shared_ptr
and std::tr1::shared_ptr
are the same thing (they are on VC++ 10, they are not for my gcc).
template<class T, class U>
typename std::enable_if<
!std::is_same< std::shared_ptr<T>, std::tr1::shared_ptr<T> >::value,
std::tr1::shared_ptr<T>
>::type
Cast( const std::tr1::shared_ptr<U>& spObject ) // rename from CastTerrainObject
{
return std::tr1::dynamic_pointer_cast<T>(spObject);
}
The following compiles on both VC++ 10 and the latest gcc. Unfortunately, it's ill-formed on VC++10 (despite working as expected)
#include <memory>
#include <type_traits>
#ifndef _WIN32
#include <tr1/type_traits>
#include <tr1/shared_ptr.h>
#endif
template<class T, class U> // rename from CastTerrainObject
std::shared_ptr<T> Cast( const std::shared_ptr<U>& spObject )
{
return std::dynamic_pointer_cast<T>(spObject);
}
template<class T, class U>
typename std::enable_if<
!std::is_same< std::shared_ptr<T>, std::tr1::shared_ptr<T> >::value,
std::tr1::shared_ptr<T>
>::type
Cast( const std::tr1::shared_ptr<U>& spObject ) // rename from CastTerrainObject
{
return std::tr1::dynamic_pointer_cast<T>(spObject);
}
struct B{ virtual ~B(){} };
struct D:B{};
int main()
{
Cast<B>(std::make_shared<D>());
}
You could also ifdef the second overload away, but I'm not sure which conditions should be checked.