2012-11-19 38 views
1

我想創建一個訪問者的工廠,返回的這些類型的對象:工廠返回的boost ::訪問者對象

class Visitor1: public boost::static_visitor<int> 
{ 
public: 
    int operator()(int&) const 
    { 
     return 1; 
    } 

    int operator()(bool&) const 
    { 
     return 1; 
    } 
}; 

class Visitor2: public boost::static_visitor<int> 
{ 
public: 
    int operator()(int&) const 
    { 
     return 2; 
    } 

    int operator()(bool&) const 
    { 
     return 2; 
    } 
}; 

我認爲,我可以返回一個類型爲boost指針:: static_visitor *對於工廠創建的對象,但這不能編譯。我也可以有對象的引用,如下所示:

Visitor1 v; 
Type t; 
boost::static_visitor<int>& vR = v; 
boost::apply_visitor(vR, t); 

我得到的錯誤是:

see reference to function template instantiation 'int boost::apply_visitor<boost::static_visitor<R>,Type>(Visitor &,Visitable &)' being compiled 
1>   with 
1>   [ 
1>    R=int, 
1>    Visitor=boost::static_visitor<int>, 
1>    Visitable=Type 
1>   ] 
1>c:\boost_1_49_0\boost\variant\variant.hpp(858): error C2064: term does not evaluate to a function taking 1 arguments 

我應該如何執行我的工廠?

回答

1

訪客使用重載,這意味着他們是一個靜態組件。工廠總是(?)意味着運行時組件。首先,確定所有衍生訪問者是否共享相同的一組過載是非常重要的。如果是這樣,你可以使用這個方案:

#include <memory> 

#include <boost/variant.hpp> 
#include <boost/variant/static_visitor.hpp> 

struct visitor_base : public boost::static_visitor<int> 
{ 
    virtual int operator()(int) = 0; 
    virtual int operator()(double) = 0; 
    virtual int operator()(const char*) = 0; 
    virtual ~visitor_base() {} 
}; 

struct impl_1 : visitor_base { 
    virtual int operator()(int) { return 1; } 
    virtual int operator()(double) { return 1; } 
    virtual int operator()(const char*) { return 1; } 
}; 

struct impl_2 : visitor_base { 
    virtual int operator()(int) { return 2; } 
    virtual int operator()(double) { return 2; } 
    virtual int operator()(const char*) { return 2; } 
}; 

std::unique_ptr<visitor_base> visitor_factory(int i) { 
    if(i == 1) { 
    return std::unique_ptr<visitor_base>(new impl_1); 
    } else { 
    return std::unique_ptr<visitor_base>(new impl_2); 
    } 
} 

int main() 
{ 
    auto vis = visitor_factory(1); 
    boost::variant<int, double, const char*> v = 3; 
    std::cout << boost::apply_visitor(*vis, v) << std::endl; 
    auto vis2 = visitor_factory(2); 
    std::cout << boost::apply_visitor(*vis2, v) << std::endl; 

    return 0; 
} 

如果您的派生遊客只是爲了適用於可能的類型的子集的變種不能用純虛函數,需要報告未能處理的某種機制基礎值(例如,例外)。

當然,示例代碼中使用的少數C++ 11功能很容易替換。

#include <memory> 
#include <string> 

#include <boost/variant.hpp> 
#include <boost/variant/static_visitor.hpp> 

struct visitor_base : public boost::static_visitor<int> 
{ 
    // the catch all 
    template <typename T> 
    int operator()(const T& t) { 
    return 0; 
    } 

    virtual int operator()(int) {} 
    virtual int operator()(double) {} 
    virtual int operator()(const char*) {} 

    virtual ~visitor_base() {} 
}; 

struct impl_1 : visitor_base { 
    virtual int operator()(int) { return 1; } 
    virtual int operator()(double) { return 1; } 
    virtual int operator()(const char*) { return 1; } 
}; 

struct impl_2 : visitor_base { 
    virtual int operator()(int) { return 2; } 
    virtual int operator()(double) { return 2; } 
    virtual int operator()(const char*) { return 2; } 
}; 

std::unique_ptr<visitor_base> visitor_factory(int i) { 
    if(i == 1) { 
    return std::unique_ptr<visitor_base>(new impl_1); 
    } else { 
    return std::unique_ptr<visitor_base>(new impl_2); 
    } 
} 

int main() 
{ 
    auto vis = visitor_factory(1); 
    boost::variant<int, double, const char*> v = 3; 
    std::cout << boost::apply_visitor(*vis, v) << std::endl; 
    auto vis2 = visitor_factory(2); 
    std::cout << boost::apply_visitor(*vis2, v) << std::endl; 

    // a variant with more than impl_1 and impl_2 can catch 
    boost::variant<int, double, const char*, std::string> vv = std::string{"asdf"}; 
    std::cout << boost::apply_visitor(*vis2, vv) << std::endl; 
    // no use one that we handle 
    vv = 3; 
    std::cout << boost::apply_visitor(*vis2, vv) << std::endl; 
    return 0; 
} 
+0

謝謝!我還留下了一個可以用來解決這個問題的界面。但是,我只適用於您提到的可能類型的子集。我曾計劃使用模板來捕獲與特定訪客實現無關的所有類型,但不能混合使用虛擬模板和模板。我該如何解決這個問題,還是需要針對與特定訪客實施無關的每種類型調用斷言。 – Baz

+0

你的意思是我應該用一個虛擬函數來替換基類中的每個純虛函數,這個虛函數會拋出一個異常? – Baz

+1

@Baz雖然無法調用模板化的operator()'virtual,但可以使用'visitor_base :: operator()'將其引入派生訪問者的範圍。 – pmr