2014-09-18 1 views
3

у меня есть подталкивание :: вариант типов, таких как:Как получить удерживаемую вариант типа, а также определить новые переменные этого типа

typedef boost::variant< uint8_t, int8_t, uint16_t, int16_t, 
       uint32_t, int32_t, float, double, std::string > StorageTt; 

А StorageTt переменной, скажем val, установлен на одном из них типы хранилищ позже в моем коде. Я хотел бы получить тип, который в настоящее время содержит val, чтобы определить больше переменных того же типа. Так что, если val в настоящее время uint16_t, я хочу сделать что-то вроде:

typedef decltype(typeid(val)) StorageTt; 
StorageT new_val = 32.0; // new_val should be a uint16_t 

, но это дает константный type_info типа. Я знаю, что я могу сделать:

switch (val.which()) { 
    case 0: // uint8_t 
    case 1: //... 

но я предпочел бы избежать длительного заявления случая, потому что я должен сделать это несколько раз.

ответ

2

Вы можете сделать что-то подобное, используя функтор посетителя с шаблоном оператора вызова:

struct MyVisitor : public boost::static_visitor<> 
{ 
    template <typename StorageT> 
    void operator()(const StorageT&) const 
    { 
     StorageT new_val = 32; // declare variable with same type 

     doSomethingWith(new_val); // do something with it 
    } 
}; 

применить его к варианту val так:

boost::apply_visitor(MyVisitor(), val); 

Ссылка:

Я не знаю способа, чтобы заменить функтор с C++ 14 родового лямбда а.

0

Используя конструктор копирования должен работать:

// construct object of same type as val 
StorageT new_val(val); 
boost::get(new_val) = 32.0; 
+0

«Как получить текущий тип варианта и определить новые переменные ** этого типа **» –

+0

В соответствии с образцом кода в вопросе, он попросил вариант того же типа, и конструктор копирования делает именно это , – egur

+0

нет, присвоив '32.0'' new_val', вы меняете свой удерживаемый тип на 'double', а OP запрашивает' uint16_t' (что невозможно fyi). –

2

Вы не можете сделать это. Переменные - синтаксические конструкции. Это имена для программных объектов. Имена существуют только в исходном коде.

Рабочий процесс следующий. Сначала вы пишете источник. Затем вы компилируете его, запускаете программу и выполняете некоторые действия, например, извлекаете значение из объекта boost::variant. На этом этапе вы не можете определить имена. Нет источника, имен, синтаксиса. Есть только объекты.

Если вам нужен новый объект того же типа, что и извлеченной из варианта, то StorageT new_val(val); создает только что (новый объект скрыт в new_val, вы получить доступ к нему с boost::get или boost::apply_visitor или любой другой).

Если вы хотите, чтобы выполнить действие на любой вариант у вас есть, и все действия выглядят то же самое, и только их типы различны (они не то же, так как типы различны, они просто посмотрите то же самое), и вы хотите избежать написания однотипных вещей несколько раз, тогда, конечно, шаблоны - ваши друзья. boost::apply_visitor с template<typename> operator() является правильным:

struct my_assignment_visitor: public boost::static_visitor<> 
{ 
    template <typename T> void operator()(T & var, double val) const 
    { 
     var = val; 
    } 
}; 

boost::apply_visitor(my_assignment_visitor(), new_val, 32.0); 
+0

Спасибо! Я дам этот выстрел – squareskittles

+0

Sweet! Тип T дает мне тип, который я ищу (uint16_t, double и т. Д.), И я могу определить новые переменные, используя это. Еще раз спасибо! – squareskittles

+0

Вы определяете все возможные переменные сразу во время компиляции, а не по одному, поскольку во время выполнения встречаются новые типы. Но если это сработает для вас, отлично. –

Смежные вопросы