3

私の C++ ライブラリには、型boost::variant<A,B>と、この型を入力として取得する多くのアルゴリズムがあります。メンバー関数の代わりに、この型にはvoid f( boost::variant<A,B>& var ). これはテンプレートでも実現できることは知っていますが、これは私のデザインには適していません。

私はこのスタイルのプログラミングに非常に満足しています:

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

しかし、このライブラリの一部のユーザーはそれに慣れておらず、Boost.Variant の概念が型定義によって隠されているため、v.f().

これを実現するには、2 つの可能性を考えることができます。1) からのオーバーライドと、2)独自のメンバー関数をboost::variant再実装して追加することです。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 に答える