2016-09-23 3 views
0

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

void operator()(const foo& ast) 
{ 
    //allways the same 
} 

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

void operator(const foo& ast) 
{ 
    for(auto&& item : ast.members) 
    { 
     boost::apply_visitor(*this, item); 
    } 
} 

и так как все другие методы, которые соответствующие для членов Арента реализованы в базовом классе, я получаю сообщение об ошибке компилятора, на этом. Теперь мой вопрос: как я могу избавиться от моего избыточного кода?

Вот пример того, как эта проблема может выглядеть:

struct variant_one; 
struct variant_two; 
struct nil{}; 
typedef boost::variant< 
    boost::spirit::x3::forward_ast<variant_one>, 
    boost::spirit::x3::forward_ast<variant_two>, 
    nil 
> example_variant; 

struct variant_one {}; 
struct variant_two 
{ 
    std::vector<example_variant> members; 
}; 


struct visitor_one : boost::static_visitor<void> 
{ 
    void operator()(const variant_one& ast) 
    { 
     std::cout << "visitor_one detected var_one" << std::endl; 
    } 

    //this is the redundant method 
    void operator()(const variant_two& ast) 
    { 
     std::cout << "visitor detected var_two, output members:" <<std::endl; 
     for(auto&& member : ast.members) 
     { 
      boost::apply_visitor(*this, member); 
     } 
    } 
} 

struct visitor_two : boost::static_visitor<void> 
{ 

    void operator()(const variant_one& ast) 
    { 
     std::cout << "visitor_one detected var_two" << std::endl; 
    } 

    //this is the redundant method 
    void operator()(const variant_two& ast) 
    { 
     std::cout << "visitor detected var_two, output members:" <<std::endl; 
     for(auto&& member : ast.members) 
     { 
      boost::apply_visitor(*this, member); 
     } 
    } 
} 
+2

предоставьте [mcve] –

ответ

2

Что-то вроде этого?

template<typename Derived> 
struct VisitorBase { 
    void operator()(const foo& ast) { 
     for(auto&& item : ast.members) { 
      boost::apply_visitor(*static_cast<Derived*>(this), item); 
     } 
    } 
}; 

struct VisitorA : VisitorBase<VisitorA> { 
    void operator()(const ItemType& item) { 
     // do stuff 
    } 
}; 

или если типы, используемые в посетителях та же/заранее известно и виртуальные функции в порядке:

struct VisitorBase { 
    void operator()(const foo& ast) { 
     for(auto&& item : ast.members) { 
      boost::apply_visitor(*this, item); 
     } 
    } 
    virtual void operator()(const ItemTypeA&) = 0; 
    virtual void opetator()(const ItemTypeB&) = 0; 
}; 

struct VisitorA : VisitorBase { 
    void operator()(const ItemTypeA& item) { 
     // do stuff 
    } 
    void operator()(const ItemTypeB& item) { 
     // do stuff 
    } 
}; 

В первом примере вы могли бы хотеть, чтобы убедиться, что вы случайно не инстанцируете шаблон с не-производного типа, например, с этим:

static_assert(std::is_base_of<VisitorBase,Derived>::value, "Derived should be derived from VisitorBase"); 

это будет по-прежнему оставить открытой возможность создания экземпляра VisitorBase -derived тип с другим размером VisitorBase в параметре шаблона, что приводит к неопределенному поведению. Так что будь осторожен.

+0

большое спасибо, я думаю, что первое должно быть прекрасным, я бы хотел избежать виртуальных методов – Exagon

+0

hmm why not only http://paste.ubuntu.com/23219932/ – sehe

+1

@ sehe Поскольку я не смог его устранить, есть несколько классов посетителей, которые используют опубликованное поведение для типа 'foo', но меняют поведение других типов на' operator() '. – user4407569