2016-09-23 58 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