2016-04-10 17 views
0

編集:は完全に私が参加大規模なプロジェクトではテンプレート内で異なるメンバー変数名を使用するにはどうすればよいですか?

をコメントで提案を対処するための質問を書き直し、ラップメッセージは、イベントは、など彼らは共通の祖先を持っていないクラスがたくさんあります異なるグループの異なる人々によって書かれています(そしてそれでも)。

これらのクラス(または構造体)のほとんどは、エラーコードと説明を示すパブリックメンバーを持っています。しかし、それらは大部分が1つのグループ内で使用されており、規約はかなり緩やかであるため、メンバーの中にはerrStrという名前を付けているものもあれば、errDescを使用するものもあります。例えば

:私は、オブジェクトを受け入れ、それが持っているものは何でもメンバ変数の値を出力します関数テンプレートを記述しようとしています

struct X { 
    // stuff here... 
    int errCode; 
    std::string errStr; 
}; 

struct Y { 
    // stuff here... 
    int errCode; 
    std::string errDesc; 
}; 

。擬似コードで

template<typename T> 
bool logError(T const& x) 
{ 
    if (x.errCode == 0) 
    return true; 

    // if (T::errStr exists) 
    // log(x.errStr); 
    // else if (T::errDesc exists) 
    // log(x.errDesc); 
    return false; 
} 

何の問題を複雑にすることは我々が使用するコンパイラが完全に準拠C++ 11ではありませんVS2012、ということです。

私はstd :: enable_if、std :: is_sameなどをしばらく悩ましてきましたが、今のところ唯一の結果はさまざまなコンパイラエラーの印象的なコレクションです。

@ T.Cによってthisが指し示されました。
VS2012がサポートしているC++ 11の機能を使用すると、非常にうまくいくことが判明しましたが、不安定になり、単純化できるかどうか、あるいは別のソリューションが提供されているのか疑問に思っていました。

ありがとうございました!

+0

比較的古いコンパイラを使用しています。これはSFINAEの簡単なexcersizeですが、私はあなたの古いコンパイラがいかにうまくそれに対処できるか分かりません。あなたが本当にC++に習熟することに興味を持っているのであれば、より良いC++コンパイラが必要です(Linuxではgcc 5.3以降が望ましい)。またはWindowsのポート。 –

+0

これは私の職場で使用されるコンパイラなので、私はそれに固執しています。 –

+0

さて、私のお勧めは、あなたがこのアプローチを使って達成しようとしていたものを達成するための他の方法を見つけることです。不自由な時代遅れのツールを使用する必要がある場合は、実行可能なオプションはありません。この古いコンパイラは、SFINAEのいくつかの形式をサポートすることができるかもしれませんが、あなたの時間を無駄にし、コンパイラで使用できないものを投稿したくありません。 XとYを仮想print()を定義するスーパークラスから派生させ、XとYにprint()を実装して、それが持つメンバ変数をすべて出力してからf()で使用します。 –

答えて

0

原則としてSFINAEを使用して関連するメンバーを検出することができますが、C++ 03(コンパイラの標準)を使用すると、メンテナンスによって簡単に壊れやすい複雑で冗長なコードになります–完全な例を下に示します。関連する技術はウェブ上の多くの場所でカバーされています。例えば。私は "C + +検出データメンバーSFINAE"とヘイ、プレスト、いくつかのGitHubコード、および他の例を探せ。基本的なグーグルを含むウェブ上の情報を見つける機能は、開発者にとって非常に重要です。だから、それを試してみてください。

メンテナンスの問題を導入せず、コードを進化させるコードがもっと簡単なので、–は、このようにアクセッサ関数のオーバーロードを単純に定義するだけなので、もっと実用的なアプローチ–です:

string errorMessageOf(X const& o) { return o.errStr; } 
string errorMessageOf(Y const& o) { return o.errDsc; } 

すべてがテンプレートである必要はありません。

通常のオーバーロードは素晴らしいです。

希望関数テンプレートは、Visual C++ 2012に動作コード、およびエラーメッセージの名前の任意の数をサポートすると、代わりにC++ 03 SFINAEを用いる

template< class Type > 
bool logError(Type const& x) 
{ 
    if (x.errCode == 0) return true; // A really dangerous thing to do 
    // Especially in Windows error code 0 a.k.a. NOERROR etc. is 
    // sometimes returned by GetLastError for a genuine failure. You 
    // should better treat it as "unknown cause". 

    clog << errorMessageOf(x) << endl; 
    return not clog.fail(); // The return value is unspecified. 
} 

例次にですデータメンバー:

#include <iostream> 
#include <stddef.h> 
#include <string> 

//----------------------------------------------- Machinery: 

namespace reusable { 
    typedef ptrdiff_t Size; 

    template< Size n > 
    struct SizeCarrier_ { char nPlusOne[n + 1]; }; 

    template< class Type, Type > 
    struct TypeFrom_; 
} // namespace reusable 

namespace my{ 
    using std::string; 

    namespace impl { 
     using reusable::SizeCarrier_; 
     using reusable::TypeFrom_; 

     struct ErrorMsgMemberId { enum Enum{ noSuch, errStrName, errDescName }; }; 

     template< class Type > 
     class ErrorMsgMemberId_ 
     { 
     private: 
      template< class U > 
      static SizeCarrier_<ErrorMsgMemberId::errStrName> 
      memberId(TypeFrom_<string U::*, &U::errStr>*); 

      template< class U > 
      static SizeCarrier_<ErrorMsgMemberId::errDescName> 
      memberId(TypeFrom_<string U::*, &U::errDesc>*); 

      template< class U > 
      static SizeCarrier_<ErrorMsgMemberId::noSuch> 
      memberId(...); 

     public: 
      static ErrorMsgMemberId::Enum const value = static_cast<ErrorMsgMemberId::Enum>(
       sizeof(memberId<Type>(0).nPlusOne) - 1 
       ); 
     }; 

     template< ErrorMsgMemberId::Enum kind > 
     struct ErrorMsgFunc_; 

     template<> 
     struct ErrorMsgFunc_<ErrorMsgMemberId::errStrName> 
     { 
      template< class Type > 
      string operator()(Type const& o) const 
      { return o.errStr; } 
     }; 

     template<> 
     struct ErrorMsgFunc_<ErrorMsgMemberId::errDescName> 
     { 
      template< class Type > 
      string operator()(Type const& o) const 
      { return o.errDesc; } 
     }; 

    } // namespace impl 

    template< class Type > 
    string errorMsgOf(Type const& o) 
    { 
     static impl::ErrorMsgMemberId::Enum const member_id = 
      impl::ErrorMsgMemberId_<Type>::value; 
     return impl::ErrorMsgFunc_<member_id>()(o); 
    } 

} // namespace my 


//----------------------------------------------- Example usage: 

struct X { 
    // stuff here... 
    int errCode; 
    std::string errStr; 
}; 

struct Y { 
    // stuff here... 
    int errCode; 
    std::string errDesc; 
}; 

struct Z { 
    // stuff here... 
    int errCode; 
}; 

int main() 
{ 
    X const x = { 1, "X::errStr" }; 
    Y const y = { 2, "Y::errDesc" }; 
    Z const z = { 3 }; 

    using namespace std; 
    cout << my::errorMsgOf(x) << endl; 
    cout << my::errorMsgOf(y) << endl; 
    //cout << my::errorMsgOf(z) << endl;  //! Fails with 'noSuch' in message. 
} 
+0

"aString"メンバーと "myString"メンバーを持つ未知数のクラスがある場合、オーバーロードが機能しません –

+0

@AlexO:自分のコードや使用しているコードに関する情報が不足しているため、不思議なことであり、問​​題の記述が非常に重要な部分を除外していることを示しています。 –

+0

私は説明に追加します –

関連する問題