Подтвердить что ты не робот

Сохранение типа в С++

Можно ли сохранить имя типа как переменную С++? Например, например:

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

Я знаю, что 99,9% времени там лучший способ сделать то, что вы хотите, не прибегая к кастованию указателей void, но мне любопытно, разрешает ли С++ подобное.

4b9b3361

Ответ 1

Нет, это невозможно в С++.

Оператор RTTI typeid позволяет получить некоторую информацию о типах во время выполнения: вы можете получить имя типа и проверить, равен ли он другому типу, но об этом.

Ответ 2

Не так, как написано, но вы можете сделать что-то подобное...

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();
// ...

Этот вид вещей может быть расширен в зависимости от того, какие функции вам нужны.

Ответ 3

Вы не можете сделать это на С++, но вы можете использовать boost любую библиотеку, а затем проверить ее тип. Пример:

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

Ответ 4

Нет, вы не можете сохранить тип напрямую, как хотите, но вместо этого можете сохранить имя типа.

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
}

Дополнительная информация доступна здесь

Ответ 5

Да, если вы сами его кодируете.

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

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

как прокомментировано ниже, я забыл, что все эти типы "foo" должны быть связаны с Foo. Foo будет, по сути, быть вашим интерфейсом.

Ответ 6

Сегодня у меня была аналогичная проблема при кодировании:
Мне нужно было сохранить полиморфический тип данных (здесь называемый 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 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!

Ответ 7

Типы не являются объектами в С++ (например, в Ruby), поэтому вы не можете хранить экземпляры типа. На самом деле типы никогда не появляются в исполняемом коде (RTTI - это просто дополнительное хранилище).

В зависимости от вашего примера, похоже, что вы ищете typedefs.

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

Обратите внимание, что typedef не сохраняет тип; это сглаживание типа.

Ответ 8

Лучше всего иметь общий базовый класс, содержащий метод загрузки, и интерфейс для загрузчиков. Это позволит другим частям программы загружать данные в общих чертах без знания класса потомков:

struct Load_Interface;

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

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

Эта конструкция позволяет избежать необходимости знать типы объектов.