2013-03-11 3 views
0

Я работаю с довольно неудобным c-интерфейсом для хранения коллекций. Класс LowLevelStorer представляет собой оболочку, которую я написал для этого интерфейса. Класс Storer - класс высокого уровня, который относится к Data. Он кэширует и связывает данные с более сложными типами данных, известными только LowLevelStorer. Остальная часть моего кода работает только с Data и не знает об LowLevelData.boost :: variant members подмножество другого boost :: variant

В приведенном ниже примере кода я хочу, чтобы члены в варианте Data были включены в вариант LowLevelData. Есть ли способ указать это другое, как я это сделал?

Я действительно не понимаю, почему приведенный ниже код компилируется и действительно, почему он действительно работает правильно. То есть void operator()(const SimplePath&, const Data& data) const берет ссылку на данные, но, кажется, правильно преобразовывает ее в объект LowLevelData при вызове void operator()(const LowLevelData& data) const. Как это может быть?

Есть ли много копий, которые здесь происходят за кулисами в отношении моих объектов данных?

#include "boost/variant.hpp" 
#include "boost/variant/apply_visitor.hpp" 
#include <vector> 

class Complex{}; 
typedef boost::variant< std::vector<Complex>, std::vector<int>, std::vector<std::string> > LowLevelData; 

class LowLevelStorer 
{ 
public: 
    LowLevelStorer(): _storeVisitor(StoreVisitor()){} 

    void operator()(const LowLevelData& data) const 
    { 
     boost::apply_visitor(_storeVisitor, data); 
    } 

private: 
    class StoreVisitor: public boost::static_visitor<> 
    { 
    public: 
     void operator()(const std::vector<Complex>&) const {} 

     void operator()(const std::vector<int>& i) const {} 

     void operator()(const std::vector<std::string>&) const {} 
    }; 

    StoreVisitor _storeVisitor; 
}; 


struct SimplePath{}; 
struct BundlePath{}; 
typedef boost::variant< SimplePath, BundlePath > Path; 

typedef boost::variant< std::vector<std::string>, std::vector<int> > Data; 

class Storer 
{ 
public: 
    Storer(const LowLevelStorer& lowLevelStorer): _converter(Converter(lowLevelStorer)){} 

    void operator()(const Path& path, const Data& data) const 
    { 
     boost::apply_visitor(_converter, path, data); 
    } 

private: 
    class Converter: public boost::static_visitor<> 
    { 
    public: 
     Converter(const LowLevelStorer& lowLevelStorer): _lowLevelStorer(lowLevelStorer){} 

     void operator()(const SimplePath&, const Data& data) const { 
      _lowLevelStorer(data); 
     } 

     void operator()(const BundlePath&, const Data& data) const { 
      _lowLevelStorer(std::vector<Complex>()); 
     } 
    private: 
     const LowLevelStorer _lowLevelStorer; 
    }; 

    const Converter _converter; 
}; 

int main() 
{ 
    Storer storer((LowLevelStorer())); 
    std::vector<int> v; 
    v.push_back(13); 
    storer(Path(SimplePath()),v); 

    return 0; 
} 

ответ

2

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

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

+0

Это в значительной степени это - данные гарантированно содержат объект, который будет вписываться в LowLevelData. – Puppy

+0

@Tony The Lion Мне все еще нужны два варианта, так как вариант Data не содержит std :: vector . Этот элемент используется интерфейсом низкого уровня, но я хочу, чтобы он был скрыт от интерфейса высокого уровня. – Baz

+1

@Baz, то почему бы не иметь вариант с двумя другими типами и передать вектор «Complex» в качестве отдельного аргумента, где это необходимо? –

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