2016-09-23 59 views
0

我面临着以下问题冗余代码: 我有升压一些游客::变种,它们都在做同样的特定类型,这里FOO,因此该方法避免的boost ::变种游客

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

在每个访客中都是一样的。 由于我不想在所有访问者中编写这种冗余方法,我尽量避免为所有访问者添加一个实现此方法的通用基类。 问题的方法调用访问者本身recursivly,像这样:

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

因为所有其他的方法,这些方法用于匹配的成员在基类的arent实现,我得到一个编译器错误,在此。 现在我的问题是,我怎样才能摆脱我的冗余代码?

这里是关于问题可能是如何看一个例子:

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派生型的可能性在模板参数中使用不同的VisitorBase衍生类型,导致未定义的行为。所以要小心。

+0

非常感谢你,我第一个想到的应该是很好,我想避免虚拟方法 – Exagon

+0

嗯,为什么不只是http://paste.ubuntu.com/23219932/ – sehe

+1

@ sehe因为我没有理解它,所以有多个访问者类共享'foo'类型的发布行为,但是其他类型的''operation()'变量行为。 – user4407569