2010-03-02 76 views
3

在我的C++庫中,我有一個類型boost::variant<A,B>以及許多將此類型作爲輸入的算法。而不是成員函數,我有這種類型的全局函數,如void f(boost::variant<A,B>& var)。我知道這也可以通過模板來實現,但這不適合我的設計。將成員函數添加到Boost.Variant中

我很精細與這種編程風格:

boost::variant<A, B> v; 
f(v); 

但一些這個庫的用戶不使用它,因爲Boost.Variant概念是由一個類型定義隱藏,他們感覺就像打電話給v.f()

爲了實現這一點,我可以考慮兩種可能性:1)重寫boost::variant和2)重新實現boost::variant並添加我自己的成員函數。我不確定這些想法是否好。你能給我一些幫助嗎?還有其他的可能嗎?

+1

3)教育用戶使用非成員函數的好處,在不改變它的情況下擴展類的可用性。 – 2010-03-02 12:52:10

+0

@Mike:我完全同意,但不幸的是,這並不容易 – 2010-03-02 13:16:48

+1

在商業環境中,它通常不是「不容易」,但不可能。 – gimpf 2010-03-02 16:22:00

回答

5

另一種可能性:使用聚合。然後,您不會直接將boost.variant暴露給庫的用戶,從而使您可以更加自由地進行未來的改進,並且可以大大簡化一些調試任務。

一般建議: 聚集較少緊密耦合不是繼承,因此在默認情況下更好的,除非你知道一個用例,你明確地想通過你的對象實例已經存在的功能只服用變種。甚至比基礎班的設計應該考慮到繼承。

聚合問題示例: 據我瞭解,免費功能已經存在,並採取變體。只是定義與變異的唯一數據成員的類,並提供公共成員函數做什麼,但與成員變種調用已有的免費功能,如

class variant_wrapper { 
    boost::variant<A,B> m_variant; 
public: 
    variant_wrapper(...) : m_variant(...) {} // whatever c_tor you need. 
    void f() { f(m_variant); } 
}; 

使用這種方法,你抽象掉的事實,你正在爲你的實現使用boost.variant(你已經通過庫的用戶的typedef來做),給你以後改變它的自由(對於優化或特性擴展或其他),你可以決定讓這些值不可變,有一個更簡單的方法來調試訪問你的算法,等等等。

聚合的缺點是,你不能只傳遞包裝一個static_visitor,但是因爲你的用戶不知道有一個變體,而你只知道傳遞成員變量,所以在這裏我沒有看到一個大問題。

最後的提示: C++不是Java。您需要修復庫的用戶...

您想要的是C#擴展方法;這些東西在C++中不存在。但是,我會而不是重新實現/實施 - 複製提升。變種(維護負擔),我會不是繼承它。儘可能使用聚合。

+0

謝謝,這個解決方案聽起來非常好,我完全理解咆哮:)對我來說,使用全局功能也是有意義的。 – 2010-03-02 13:16:11

2

我從boost :: variant派生。這應該沒問題,只要你不添加數據成員到類中,並且不要添加虛函數。 (你也許可以做一些這樣的事情,但是我認爲事情會更加複雜一些)。無論如何,這似乎對我來說行得通。

#include "boost/variant.hpp" 
#include <iostream> 

template<typename T1, typename T2> 
struct my_print : public boost::static_visitor<> 
{ 
    void operator()(T1 t1) const 
    { 
    std::cout<<"FIRST TYPE "<<t1<<std::endl; 
    } 
    void operator()(T2 t2) const 
    { 
    std::cout<<"SECOND TYPE "<<t2<<std::endl; 
    } 
}; 

template<typename T1, typename T2> 
class MyVariant : public boost::variant<T1,T2> 
{ 
    public: 
    void print() 
    { 
     boost::apply_visitor(my_print<T1,T2>(), *this); 
    } 

    template<typename T> 
    MyVariant<T1,T2>& operator=(const T& t) 
    { 
     boost::variant<T1,T2>::operator=(t); 
     return *this; 
    } 

    MyVariant(const T1& t) : boost::variant<T1,T2>(t) 
    { 
    } 

    MyVariant(const T2& t) : boost::variant<T1,T2>(t) 
    { 
    } 

    template<typename T> 
    explicit MyVariant(const T& t) : boost::variant<T1,T2>(t) 
    { 
    } 
}; 

int main() 
{ 
    MyVariant<int,std::string> s=1; 
    s.print(); 
    s=std::string("hello"); 
    s.print(); 

    MyVariant<int,std::string> v2 = s; 
    v2.print(); 

    s=boost::variant<int,std::string>(3); 
    s.print(); 
}