2016-10-31 5 views
2

私の現在のプロジェクトでは、LinuxとWindows用に同時にビルドしています。 残念ながら、私たちのMSVCのプラットフォームの問題のいくつかは非常に古いためです。私たちはMSVC 2010を使用しています.gccは比較的新しいものを使用していますが、よりスマートなものにはバージョン4.8があります。標準出力:: 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は私がのstd :: tr1を:: shared_ptrのための2番目のオーバーロードを追加した後しつこい始めました。 コンパイルエラーは、私が繰り返し取得しています:

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

それらのうちの1つが「shared_ptrを使用しています=もう1つ」であるかもしれません。その場合、同じタイプであり、オーバーロードに使用することはできません。 –

+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が同じものであれば、2番目のオーバーロードを無効にします(これらは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の両方で次のコンパイルが行われます。残念ながら、それは(として期待される作業にもかかわらず)

#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

VC++ 10の上に病気に形成されたのですまた、2番目のオーバーロードIFDEF離れでしたが、私は確認すべき条件はよく分かりません。

+0

このアプローチは、私の視点からの#ifdefアプローチよりもはるかに優れています。 Testing now –

+0

唯一の欠点は、コンパイルされたプログラムが悪いということです。この手法はC++では有効ではありませんが、テンプレート関数の特殊化が有効でないことをHalt-hardと判断した場合には、標準では診断は必要ありません。 – Yakk

+0

@ Yakkなぜそれが悪いのですか? – krzaq

2

これは、1つのtemplate機能にstd::tr1::shared_ptrまたはstd::shared_ptrのどちらかを取ることができCastです。これは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は、テンプレートのテンプレート引数を推測properyないかもしれないということです(つまり、C++ 03で、私が意味するが、これはMSVC2010である)、またはそのstd::tr1::shared_ptrはalisingのctorのを欠落している可能性があります。

あなたがstd::shared_ptrまたはstd::tr1::shared_ptrでのみ仕事にCastを制限する必要がある場合は、Sp<U>は、これら二つのうちの一つであることをSFINAEテストを追加することができます。

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

しかし、これは必須ではありません。同じタイプのシステムではテストは冗長になりますが、冗長テストは合法です。冗長オーバーロードはありません。

+1

タイプエイリアスを使用からtypedefに変更すると、VC10でコンパイルされます。 – krzaq

関連する問題