2

私は、メンバ変数のマップを文字列キーに関連付けて実装しています。 すべての変数はベースクラス "BaseA"からの範囲です マップから変数にアクセスする場合は、元のタイプを取得する必要がないように、ベースクラスのメソッド(サンプルではgetDesc()を使用する必要があります)。多相メンバ変数のポインタstd :: map

このコードはGNU g ++ 6.2.1でコンパイルして実行しますが、私が読んだことによると、reinterpret_castの使用は移植性がなく、他のコンパイラでは動作しない可能性があります。 これが正しいですか?あるいは、このコードはC++標準に準拠していますか? reinterpret_castを使用せずにこれを行う他の方法はありますか? "Vars"は、デフォルトのコピーコンストラクタとコピー割り当ての実装でコピー可能でなければならないという要件があります。

サンプルコード:

#include <iostream> 
#include <sstream> 
#include <map> 
#include <typeinfo> 

using namespace std; 

struct BaseA 
{ 
    virtual string getDesc() = 0; 
}; 

struct A1 : BaseA 
{ 
    string getDesc() override { return "This is A1"; } 
}; 

struct A2 : BaseA 
{ 
    string getDesc() override { return "This is A2"; } 
}; 

struct Vars 
{ 
    A1 a1; 
    A2 a2; 

    map< string, BaseA Vars::* > vars; 

    Vars() 
    { 
     vars["A1_KEY"] = reinterpret_cast<BaseA Vars::*>(&Vars::a1); 
     vars["A2_KEY"] = reinterpret_cast<BaseA Vars::*>(&Vars::a2); 
    } 

    BaseA& get(const string& key) 
    { 
     auto it = vars.find(key); 
     if (it != vars.end()) 
     { 
      return this->*(it->second); 
     } 
     throw std::out_of_range("Invalid variable key:[" + key + "]"); 
    } 
};         

int main() 
{ 
    Vars v; 

    cout << "a1 description :" << v.get("A1_KEY").getDesc() << endl; 
    cout << "a2 description :" << v.get("A2_KEY").getDesc() << endl; 

    return 0; 
} 
+1

関連性のない種類ですが、 'std :: string'を' std :: map'のキーとして使用することをお勧めします。可能であれば(ほとんどの場合)、 'enum'を使用してください。 – DeiDei

+0

ありがとうDeiDei。私は列挙型を使用することができますが、この場合、キーはコマンドラインとしてユーザーによって入力されるため、文字列がよりよく適合することを理解しています – SNJ

答えて

2

はい、reinterpret_castがどうなるかについてvery few guaranteesがあり、そしてあなたは、元の形に戻ってキャストしない限り、他のメンバーに1つのポインタからキャストすると、(そのうちの一つではありません、それは本当にあなたを助けません)。

これを行うには、安全かつ簡単な方法はstd::functionを使用している:

struct Vars 
{ 
    A1 a1; 
    A2 a2; 

    map< string, std::function<BaseA&(Vars&)> > vars; 

    Vars() 
    { 
     vars["A1_KEY"] = &Vars::a1; 
     vars["A2_KEY"] = &Vars::a2; 
    } 

    BaseA& get(const string& key) 
    { 
     auto it = vars.find(key); 
     if (it != vars.end()) 
     { 
      return it->second(*this); 
     } 
     throw std::out_of_range("Invalid variable key:[" + key + "]"); 
    } 
}; 

注変更するvars辞書を必要としたことがないならば、あなたはstatic constメンバーにそれを回すことができること。 (これは、ソースファイルのクラス外で定義して初期化する必要があることを意味します)。

+0

どうしたらうまくいくのか説明できますか? &Vars :: a1'は関数に変換されますか? – Phil1970

+0

@ Phil1970スタンダードは、メンバーへのポインタが有効な['Callable'](http://en.cppreference.com/w/cpp/concept/Callable)であり、 'arg * * ptm'か'(* arg)。* ptm'のどちらかを実行します。だから '[ptm](Vars&v) - > BaseA&{return v。* ptm; } '(ただし、コンパイラ固有のライブラリ*は' reinterpret_cast'のようなものを安全に使うことができるので、より効率的です。) – aschepler

+0

ありがとうaschepler !!!これは私が探しているものです! – SNJ

関連する問題