Kadir Erdem Demir Kadir Erdem Demir - 1 month ago 7
C++ Question

Casting std::tr1::shared_ptr<T> and std::shared_ptr<T> with same function but different overloads

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?

Answer

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

#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>());
}

demo

You could also ifdef the second overload away, but I'm not sure which conditions should be checked.