转换 std::tr1::shared_ptr<T> 和 std::shared_ptr<T> 具有相同的功能但不同的重载
Casting std::tr1::shared_ptr<T> and std::shared_ptr<T> with same function but different overloads
在我当前的项目中,我们同时为 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>'
你们有办法解决我的问题吗?
使您的 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);
}
原答案留给后人。 它在 VC++ 上的格式不正确(尽管它按预期工作),因为没有有效的函数特化。
如果 std::shared_ptr
和 std::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>());
}
您也可以通过 ifdef 消除第二个重载,但我不确定应该检查哪些条件。
这是一个 Cast
,可以在一个 template
函数中使用 std::tr1::shared_ptr
或 std::shared_ptr
。这遵循 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_ptr
和 std::shared_ptr
。
你写的任何模板函数都必须有一组模板参数,如果你传入它们,模板就是有效的。不这样做会使您的程序格式错误,不需要诊断。
我担心的是 MSVC2010 可能不会 属性 推导模板模板参数(我的意思是,那是 C++03,但这是 MSVC2010),或者 std::tr1::shared_ptr
可能会丢失alising ctor.
如果您需要限制 Cast
仅适用于 std::shared_ptr
或 std::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> >{}
但我怀疑这是必需的。在相同类型的系统上,测试变得多余,但冗余测试是合法的,冗余重载不是。
在我当前的项目中,我们同时为 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>'
你们有办法解决我的问题吗?
使您的 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);
}
原答案留给后人。 它在 VC++ 上的格式不正确(尽管它按预期工作),因为没有有效的函数特化。
如果 std::shared_ptr
和 std::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>());
}
您也可以通过 ifdef 消除第二个重载,但我不确定应该检查哪些条件。
这是一个 Cast
,可以在一个 template
函数中使用 std::tr1::shared_ptr
或 std::shared_ptr
。这遵循 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_ptr
和 std::shared_ptr
。
你写的任何模板函数都必须有一组模板参数,如果你传入它们,模板就是有效的。不这样做会使您的程序格式错误,不需要诊断。
我担心的是 MSVC2010 可能不会 属性 推导模板模板参数(我的意思是,那是 C++03,但这是 MSVC2010),或者 std::tr1::shared_ptr
可能会丢失alising ctor.
如果您需要限制 Cast
仅适用于 std::shared_ptr
或 std::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> >{}
但我怀疑这是必需的。在相同类型的系统上,测试变得多余,但冗余测试是合法的,冗余重载不是。