2012-08-14 64 views
1

我也有幾類與查訪功能,像這樣:模板和樣式位訪客

struct Person { 
    std::string name; 
    unsigned age; 

    template<class Visitor> 
    void visit(Visitor& c) 
    { 
     c("name", name); 
     c("age", age); 
    } 

    template<class Visitor> 
    void visit(Visitor& c) const 
    { 
     c("name", name); 
     c("age", age); 
    } 
}; 

我有這樣一個訪問者:

struct PrintVisitor 
{ 
    PrintVisitor(std::ostream& stream) 
     : m_stream(stream) 
    {} 

    template<class T> 
    void operator()(const std::string& name, const T& v) 
    { 
     m_stream << name << ": " << v << std::endl; 
    } 

private: 
    std::ostream& m_stream; 
}; 

對每一個參觀者我想定義流操作:

std::ostream& operator<<(std::ostream& stream, const Person& p) 
{ 
    PrintVisitor printer(stream); 
    p.visit(printer); 
    return stream; 
} 

是否有可能提供一個單一的運營商< <一個接受可以上課嗎?

(現在,我只是嘗試印刷,但其實我是想實現 JSON序列化,反序列化,也許平等,低於運營商。

UPDATE

我用戴維斯溶液:

基類CRTP:

template <class T> 
struct Visitable {}; 

所有的Visitable類從那裏繼承:

struct Person : Visitable<Person> { ... } 

運算符和函數模板的左右,而使用靜態澆鑄訪問類:

template<class T> 
std::ostream& operator<<(std::ostream& stream, const Visitable<T>& p) 
{ 
    PrintVisitor printer(stream); 
    static_cast<const T&>(p).visit(printer); 
    return stream; 
} 
+4

我有解析困難「是否有可能不需要在模板函數中實現一次運算符」 – PlasmaHH 2012-08-14 13:18:14

+0

謝謝,更正。 – nishantjr 2012-08-14 13:21:29

回答

1

,你正在服用的方法類似於如何boost實現了序列化庫,不同之處在於它們超載operator&(二進制而不是地址)與庫進行交互。然後訪問者將使用該類型的單個serialize操作。

現在的問題是,我真的不明白的問題:

是否有可能不必在模板函數只有一次實施操作?

你的意思是提供一個單一的operator<<,它將採用任何訪客(串行器)類型?如果這是個問題,並且沒有詳細說明,你可以嘗試使用繼承和CRTP來解決這個問題。在所有訪問者的模板化基礎中實現運算符作爲成員函數,並將具體訪問者作爲參數。

我不太確定這將如何適用於比較運算符,而operator<<operator>>看起來很自然的序列化,他們會出乎意料的任何其他操作。

+0

所以我有一個基本模板類,它實現了我希望訪問者擁有的所有操作/操作符。謝謝 – nishantjr 2012-08-14 13:45:48

+0

@njr:Google for CRTP,它不像*創建基類那樣簡單,能夠執行你想要的代碼,你需要一些模板hackery。 – 2012-08-14 13:48:11

+0

謝謝,我有一切工作,有趣的是,我的基類的定義是空的。 – nishantjr 2012-08-14 16:34:01

0

你的意思是你想要做這樣的事嗎?

template<class Visitable> 
std::ostream& operator<<(std::ostream& stream, const Visitable& v) 
{ 
    PrintVisitor printer(stream); 
    v.visit(printer); 
    return stream; 
} 

這當然會引起歧義。你想要的是這樣的:

template<class Visitable implements visit> 
std::ostream& operator<<(std::ostream& stream, const Visitable& v) 
{ 
    PrintVisitor printer(stream); 
    v.visit(printer); 
    return stream; 
} 

我不知道這是否可能。

你也可以這樣做:

class Visitable { ... } 
class Person : public Visitable { ... } 

,然後實現正常功能:

std::ostream& operator<<(std::ostream& stream, const Visitable& v) 

但你有一個虛函數調用的一個小的開銷。

+1

這種方法的問題在於,這種模板化的重載會導致一些「操作符<<標準中提供的 – 2012-08-14 13:47:25

+0

是的,我知道,我只是澄清你想要做什麼,你只希望這個模板在Visitable已經實現了訪問函數時實例化,我不清楚這是否可以實現通過模板專門化,SFINAE等等(顯然它可以通過繼承完成,你可以創建一個基類Visible,然後實現一個普通的非模板化函數) – 2012-08-14 14:19:17