3

在我的 C++ 库中,我有一个类型boost::variant<A,B>和许多算法将这种类型作为输入。我在这种类型上有全局函数,而不是成员函数,比如void f( boost::variant<A,B>& var ). 我知道这也可以用模板来实现,但这不适合我的设计。

我对这种编程风格非常满意:

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

但是这个库的一些用户并不习惯,而且由于 Boost.Variant 的概念被类型定义所隐藏,他们觉得调用v.f().

为了实现这一点,我可以想到两种可能性:1)覆盖boost::variant和 2)重新实现boost::variant和添加我自己的成员函数。我不确定这些想法是否好。你能给我一些帮助吗?还有其他可能性吗?

4

2 回答 2

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++ 中不存在。但是,我不会重新实现/实现复制 boost.variant(维护负担),也不会继承它。尽可能使用聚合。

于 2010-03-02T09:07:36.393 回答
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();
}
于 2010-03-02T09:06:44.990 回答