4

文字列または文字をクラス メンバー/メンバー関数に変換して動的にアクセスする方法はありますか?

例のために。この特定のコード、

 #include <iostream>
 #include <map>

 using namespace std;

 class agnt {
 public:
 int x, y;
 agnt(int a=0, int b=0) : x(a), y(b) {}
 };


 int main() {
      map<int,agnt> agntID;
      agnt temp;
      temp.x=1;
      temp.y=5;

      agntID[1]=temp;

      for(char tmp='x'; tmp<'z'; tmp++) {
         cout<<agntID[1].tmp<<'\n';     //Here I get the following error: tmp is
         }                              //not a member of class agnt
 }

クラスメンバーとして識別されるように文字「tmp」を変換する方法はありますか? ヒントや解決策をいただければ幸いです。

4

4 に答える 4

1

C++ は静的型付け言語であるため、これを行うことはできません。この種の動作を取得する 1 つの方法は、アクセスするラッパーを提供することです。

template <char c>
struct getter {
};


template <>
struct getter<'x'> { 
   static int get(const agnt &theAgnt) {
      return theAgnt.x;
   }
};


template <>
struct getter<'y'> { 
   static int get(const agnt &theAgnt) {
      return theAgnt.y;
   }
};

template <char c>
int get(const agnt &theAgnt) {
    return getter<c>::get(theAgnt);
}

そして次のように呼び出します:

agnt temp;
//... set members
std::cout << get<'x'>(temp) << std::endl;

ただし、forテンプレート パラメーターはコンパイル時に決定する必要があるため、ループは期待どおりには機能しません。また、のような何らかの NULL インジケーターを返すgetunspecialized で関数を定義しない限り、古いものを要求することはできません。getterINT_MIN

ただし、これはすべて、動的言語に漠然と似たものを取得するためのハックしかし、それは単に を参照することと実際には何の違いもありませんtemp.x。代わりに、C++ の規則に従って、静的型付けを楽しむようにしてください。

于 2013-10-24T05:54:26.340 に答える
1

いいえと答えた人は皆正しいのですが....それは全体像を物語っていません。言語にはそれを許可するものは何もありませんが、それは環境がそれを許可しないという意味ではありません。

たとえば、vxworks では、 を呼び出しsymFindByName()て関数、変数、またはその他のシンボルを検索し、それが提供するポインターを介して関数を呼び出すことができます。しかし、これは OS API に依存しており、おそらく vxworks リンカーの動作方法の副作用です。

他の OS にも同様の機能がある場合があります。

于 2013-10-24T07:45:59.870 に答える
1

いいえ

C++ には、イントロスペクションとリフレクションの機能がありません。この種の動的アクセスは、自分でコーディングする必要があります。

ハンド コーディングに代わる合理的な方法として、場合によっては、外部スキーマ ファイルを使用して C++ クラスを記述し、クラスとイントロスペクションおよびリフレクション コードを自動的に生成することができます。テンプレートを使用してこれを行うことはできません。C++ のメタプログラミング機能でさえ、この領域にはまったく存在しないからです。

一般に、直接解析.hしてコードを生成することは、C++ 構文が非常に複雑であるため、はるかに困難になる可能性があります (コンパイラ メーカーでさえ、有効な C++ コードとそうでないものについてかなりの程度に同意するのにかなりの年月がかかりました)。

テンプレートを使用して公開を簡素化できますが、手動で行うこともできます。

template<typename T, typename C>
std::map<std::string, T C::*>& attribute_map() {
    static std::map<std::string, T C::*> m;
    return m;
}

template<typename C>
struct Published {
    template<typename T>
    T& attribute(const std::string& name) {
        std::map<std::string, T C::*>& m = attribute_map<T, C>();
        typename std::map<std::string, T C::*>::const_iterator i=m.find(name);
        if (i == m.end()) {
            throw std::runtime_error("Attribute not present");
        } else {
            return static_cast<C *>(this)->*i->second;
        }
    }
};

各属性について、明示的に「公開」する必要があります

template<typename T, typename C>
void publish(const std::string& name, T C::*mp) {
    attribute_map<T, C>()[name] = mp;
}

上記のボイラープレート コードを指定すると、クラスを作成し、次のように派生してそのメンバーの一部を公開できますPublished<Class>

struct MyClass : Published<MyClass> {
    int a;
    double b;
    std::string c;

    MyClass(int a, double b, const std::string& c)
        : a(a), b(b), c(c)
    {
    }
};

次に、プログラムの開始時に一度だけ関数を呼び出して、publish属性に動的にアクセスできるようにする必要があります。

int main(int argc, const char *argv[]) {
    publish("a", &MyClass::a);
    publish("b", &MyClass::b);
    publish("c", &MyClass::c);

    MyClass m1(3, 4.5, "This is a test");
    MyClass m2(6, 7.8, "This is another test");

    std::cout << m1.attribute<int>("a") << "\n";
    std::cout << m2.attribute<std::string>("c") << "\n";
    return 0;
}
于 2013-10-24T05:53:19.283 に答える