2016-10-31 57 views
2

在我当前的项目中,我们正在同时为Linux和Windows构建。 不幸的是,因为有些平台问题,我们的MSVC非常陈旧。我们使用的是MSVC 2010.而gcc我们使用的是相对较新且更智能的版本,其版本为4.8。Casting std :: tr1 :: shared_ptr <T>和std :: shared_ptr <T>具有相同的功能但重载不同

下面的代码编译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); 
} 

MSVC开始唠叨后,我增加对性病:: TR1 :: shared_ptr的第二个过载。 编译错误,我反复得到:

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

你们是否有我的情况的解决方案?

+0

'#ifdef'它在平台上不起作用吗? – Yakk

+0

它可能是其中一个是'使用shared_ptr =另一个'。在这种情况下,它是相同的类型,不能用于重载。 –

+0

@Yakk我希望我可以轻松地进行测试,但是一旦我做出改变,自动生成机器就会被触发并且生成过程需要1-2小时。不幸的是,我需要确保首先应用。 –

回答

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第二超载了,但我不知道哪些情况需要检查一下。

+0

从我的角度来看,这种方法比#ifdef方法好得多。现在测试 –

+0

唯一的缺点是你最终会遇到一个不适合编译的程序。这种技术不是合法的C++,但标准状态在这种情况下不需要诊断(因为确定模板函数没有专门化可以是有效的)。 – Yakk

+0

@Yakk为什么它不合格? – krzaq

2

这是一个Cast,可以采取任一std::tr1::shared_ptrstd::shared_ptr在一个template功能。在此之前,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可能会丢失aling ctor。

如果您需要限制Cast仅与std::shared_ptrstd::tr1::shared_ptr工作,你可以添加一个SFINAE测试Sp<U>是这两个中的一个。

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

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

+1

将类型别名从使用改为typedef后,它在VC10上编译。 – krzaq

相关问题