web-dev-qa-db-ja.com

C ++での型の格納

型名をC++変数として格納することはできますか?たとえば、次のようになります。

type my_type = int; // or string, or Foo, or any other type
void* data = ...;
my_type* a = (my_type*) data;

99.9%の時点で、voidポインターをキャストせずに目的の操作を実行できるより良い方法があることはわかっていますが、C++でこの種のことが許可されているかどうか知りたいです。

31
perimosocordiae

いいえ、これはC++では不可能です。

RTTI typeid演算子を使用すると、実行時に型に関するいくつかの情報を取得できます。型の名前を取得して、それが別の型と等しいかどうかを確認できますが、それだけです。

23
Thomas

書いた通りではありませんが、同様のことができます...

class Type
{
    public:
        virtual ~Type(){}
        virtual void* allocate()const=0;
        virtual void* cast(void* obj)const=0;
};

template<typename T> class TypeImpl : public Type
{
      public:
         virtual void* allocate()const{ return new T; }
         virtual void* cast(void* obj)const{ return static_cast<T*>(obj); }
};

// ...
Type* type = new TypeImpl<int>;
void* myint = type->allocate();
// ...

この種のものは、必要な機能に応じて拡張できます。

16

C++ではそれはできませんが、boost anyライブラリを使用して、それが保持する型をテストできます。例:

bool is_int(const boost::any & operand)
{
  return operand.type() == typeid(int);
}

http://www.boost.org/doc/libs/1_42_0/doc/html/any/s02.html

9
Chris H

いいえ、型を直接保存することはできませんが、代わりに型の名前を保存できます。

_const char* str = typeid(int).name();
_

その変数を比較に使用することを計画しているときはいつでも、代わりにそのときにstr変数を型のname()と比較できます。

_const char* myType = typeid(int).name();

//....

//Some time later:
if(!strcmp(myType, typeid(int).name()))
{
  //Do something
}
_

詳細はこちら

6
Brian R. Bondy

はい、自分でコーディングした場合。

enum Foo_Type{
    AFOO,
    B_AFOO,
    C_AFOO,
    RUN
};

struct MyFoo{
    Foo_Type m_type;
    Boost::shared_ptr<Foo> m_foo;
}

以下にコメントするように、私が省略したのは、これらすべての「foo」タイプはFooに関連している必要があるということでした。本質的に、Fooはあなたのインターフェースになります。

3
wheaties

今日、コーディング中に同様の問題が発生しました:
私はそれを実装する具象クラスの呼び出し関数の上に多相データ型(ここではrefobj)を保存する必要がありました。コード量を減らす必要があるため、変数を明示的にキャストしないソリューションが必要です。

私のソリューション(ただし、まだテストしていません)は、以前の回答に似ています。実際にはかなり実験的な解決策です。こんな感じ...

// interface to use in the function

class Type   
{
public:
    virtual void* getObj()const=0;
};

// here the static_cast with the "stored" type

template<typename T> class TypeImpl : public Type
{
public:
    TypeImpl(T *obj) {myobj=obj;}
    virtual void* getObj()const{ return static_cast<T*>(myobj); }

private: 
    T* myobj;
};

// here the type that will contain the polimorific type
// that I don't want to cast explicitly in my code
Type *refobj;

// here the "user code "
void userofTypes()
{
    ( refobj->getObj() ).c_str(); 
    // getObj() should return a string type over which
    // calling string concrete functions ...let's try!
}

void main()
{
    refobj=new TypeImpl < string > ( new string("hello") );
    userofTypes();
}
// it might seem absurd don't cast refobj explicitly, but of
// course there are situation in which it can be useful!
2
David

型はC++のオブジェクトではないため(たとえば、Rubyの場合)、型のインスタンスを格納することはできません。実際、型は実行コードに表示されません(RTTIは単なる追加のストレージです)。

あなたの例に基づいて、typedefを探しているように見えます。

typedef int Number;
Number one = 1;
Number* best = (Number*) one;

Typedefはstoring型ではないことに注意してください。 エイリアスタイプです。

1

より良いプロセスは、loadメソッドを含む共通の基本クラスと、loadersのインターフェイスを持つことです。これにより、プログラムの他の部分は、子孫クラスの知識がなくても一般的にデータをロードできます。

struct Load_Interface;

struct Loader
{
  virtual void visit(Load_Interface&) = 0;
}

struct Load_Interface
{
  virtual void accept_loader(Loader& l)
    {
        l.visit(*this);
    }
};

この設計により、オブジェクトのタイプを知る必要がなくなります。

1
Thomas Matthews