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

У меня есть импульс:: вариант таких типов, как:

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;
StorageTt new_val = 32.0;  // new_val should be a uint16_t

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

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

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

3 ответа

Решение

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

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.

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

Рабочий процесс выглядит следующим образом. Сначала вы пишете источник. Затем вы компилируете его, запускаете программу, и она выполняет некоторые действия, например, получает значение из 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);

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

// construct object of same type as val
StorageT new_val(val);
boost::get(new_val) = 32.0;
Другие вопросы по тегам