C++ Boost:: вариант универсального конвертера

В течение последних трех дней я пытался выяснить, как реализовать общий способ получения значения из boost:: variable<...>, но это было довольно сложно.

Вот решение, которое я мог бы придумать, но оно совсем не общее:

#include <iostream>
#include "boost\variant\variant.hpp"

using MyVariant = boost::variant<int, std::string>;

class VariantConverter : public boost::static_visitor<>
{
private:
    mutable int _int;
    mutable std::string _string;

    static VariantConverter apply(MyVariant& v) 
    {
        VariantConverter res;

        v.apply_visitor(res);

        return res; // copy will be elided, right?
    }

public:
    void operator()(int& i) const
    {
        _int = i;
    }

    void operator() (std::string& s) const
    {
        _string = s;
    }

    static int to_int(MyVariant v) 
    {
        return apply(v).from_int();
    }

    static std::string to_string(MyVariant v) 
    {
        return apply(v).from_string();
    }

    int from_int() 
    { 
        return _int; 
    };

    std::string from_string() 
    { 
        return _string; 
    };
};

int main()
{
    using namespace std;

    MyVariant v = 23;

    int i = VariantConverter::to_int(v);

    cout << i << endl;

    v = "Michael Jordan";

    std::string s = VariantConverter::to_string(v);

    cout << s.c_str() << endl;

    cin.get();

    return 0;
}

Буду признателен, если кто-нибудь поможет мне найти лучшее решение.

Или, возможно, кто-то может объяснить мне обоснование этого:

если я объявлю:

using MyVariant = boost::variant<int, std::string>;

а затем:

ConverterToInt : basic_visitor<int> {
public:
    int operator() (int i) { return i; };
};

Почему когда я пытаюсь применить ConverterToInt к MyVariant как таковой:

ConverterToInt cti;

MyVariant i = 10;

i.apply_visitor(cti);

Я получаю ошибку компилятора при попытке найти оператор (), который принимает std::string?

Мне кажется, что apply_visitor пытается вызвать operator() для каждого из типов, которые может принимать MyVariant. Это так? Если это так, почему? Как я могу избежать этого поведения?

Ура!

2 ответа

Вы можете избежать сообщения об ошибке, сказав ConverterToInt что делать с std::string, Вы можете знать, что i не может быть std::string но не стоит ожидать, что компилятор это знает (и если это правда, почему вы используете вариант?).

apply_visitor буду называть только правильный operator() метод, но он решает во время выполнения, и компилятор должен иметь все возможности для генерации кода.

MyVariant iv = 10;    
int i = boost::get<int>(iv);

boost::variable не "вызывает" каждый оператор () интерфейса при вызове, но он должен это делать. Вот и весь смысл. Вариант может содержать любой из типов шаблонов, поэтому, если вы хотите определить операцию над ним, вы должны где-то указать, что эта операция означает для каждого типа.

Другие вопросы по тегам