使用相同的函数但不同的重载强制转换std :: tr1 :: shared_ptr <t>和std :: shared_ptr <t>

时间:2016-10-31 09:33:35

标签: c++ c++11 visual-c++ shared-ptr

在我目前的项目中,我们同时为Linux和Windows构建。 不幸的是,因为某些平台问题我们的MSVC已经很老了。我们正在使用MSVC 2010.而gcc我们使用的是相对较新且更智能的版本4.8。

以下代码在gcc中编译,但MSCV对此进行了唠叨:

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

在我为std :: tr1 :: shared_ptr添加第二个重载后,MSVC开始唠叨。 我反复得到的编译错误:

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>'

你们有解决方案吗?

2 个答案:

答案 0 :(得分:2)

使您的Cast功能模板采用模板模板参数:

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

demo

留下后代的原始答案。 它在VC ++上是不正确的(虽然它按预期工作),因为没有有效的函数专门化。

如果std::shared_ptrstd::tr1::shared_ptr相同,则禁用第二次重载(它们在VC ++ 10上,它们不适用于我的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);
}

以下编译VC ++ 10和latest gcc。不幸的是,它在VC ++ 10上形成不良(尽管按预期工作)

#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

你也可以ifdef第二次过载,但我不确定应该检查哪些条件。

答案 1 :(得分:2)

这是一个Cast,可以在一个std::tr1::shared_ptr函数中 <{em> std::shared_ptrtemplate。这是继DRY(不要重复自己)并避免使用替代解决方案的微妙陷阱:

template<class T, template<class>class Sp, class U>
Sp<T> Cast( const Sp<U>& spObject )
{
  typedef Sp<T> R;
  // manual implementation of the dynamic shared cast
  // as we don't know if we want to use tr1 or not:
  T* out = dynamic_cast<T*>(spObject.get());
  if (!out)
    return R();
  // alising ctor, shares refcount block with spObject 
  // but uses out pointer:
  return R( spObject, out ); 
}

这是合法的C ++,应该适用于std::tr1::shared_ptrstd::shared_ptr

您编写的任何模板函数都必须具有一组模板参数,如果您将其传入,则模板有效。如果不这样做,会导致您的程序格式错误,无需诊断。

live example

我担心的是,MSVC2010可能无法推断模板模板参数(我的意思是,这是C ++ 03,但这是MSVC2010),或者std::tr1::shared_ptr可能缺少alising ctor。

如果您需要限制Cast只能使用std::shared_ptrstd::tr1::shared_ptr,则可以添加Sp<U>是其中之一的SFINAE测试。

std::is_same< std::shared_ptr<U>, Sp<U> >{}
|| std::is_same< std::tr1::shared_ptr<U>, Sp<U> >{}

但我怀疑这是必须的。在相同类型的系统上,测试变得多余,但是冗余测试是合法的,冗余过载不是。