4

この問題があります(ヒストグラム)。私は実際のスペースを持っています:[a,b]何らかの方法で分割されています ( [a0=a, a1, a2, ..., b])。パーティショニングは、等間隔 ( a1 - a0 = a2 - a1 = ...) または変数で行うことができます。

これを処理するクラスが必要です。それが属するパーティションのビンの値を指定して、いくつかのメソッドを使用します。特定のビンなどの中心を見つける他の方法。

プログラム中に、次のような単純な関数を呼び出すためだけにクラスをインスタンス化するのは好きではありません

Binner binner(binning);
binner.get_bin(1.3);
binner.get_centerbin(2);

だから私はそのようなことをするためにテンプレートを使って静的クラスを書こうとしました:

Binner<binning>::get_bin(1.3);
Binner<binning>::get_centerbin(2);

それは良い考えですか?それを行う他の方法はありますか?今、私は次のような無料の機能を持っています

double get_bin(double bin, Binning binning); // a lot of if/else inside

しかし、エラーが発生しやすいと思います。

ここで私の実装:

enum Binning {CELL, LARGE, BE};
const double binning_LARGE[] = {0, 1.2, 1.425, 1.550, 1.800, 2.5};
const double binning_BE[] =  {0, 1.425, 1.550, 2.5};

template<Binning binning>
class Binner
{
public:
    static const double* bins;
    static const int n;
    static int get_bin(double value);
};

template<> const double* myclass<LARGE>::bins = binning_LARGE;
template<> const double* myclass<BE>::bins = binning_BE;

template<> const int myclass<LARGE>::n = sizeof(binning_LARGE) / sizeof(double);
template<> const int myclass<BE>::n = sizeof(binning_BE) / sizeof(double);

template<Binning binning> int myclass<binning>::get_bin(double value)
{
    return find_if(bins, bins + n,
           bind2nd(greater<double>(), value)) - bins - 1;
}

template<> int myclass<CELL>::get_bin(double value)
{
    return static_cast<int>(value / 0.025);
}
  1. それは良い実装/設計ですか?
  2. nを使用してフィールドを回避する方法はありstd::vectorますか? どのように?
  3. をパラメータ化する方法はあり0.025ますか? doubleテンプレートパラメータにできないことはわかっていますが、次のようなものを書くことはできますか:

    Binner<0.025> binner;
    
  4. その他/アドバイス?

編集:

3番目のポイントについてなぜ私はそれができないのか:

template<Binning binning, int N=100>
class Binner
{
public:
    static const double* bins;
    static const int n;
    static int bin(double value);
};

...

template<Binning binning, int N> int Binner<CELL, N>::bin(double value)
{
    return static_cast<int>(value / (2.5 / N));
}
4

3 に答える 3

4

IMHO、クラスをインスタンス化したくない場合は、設計は問題ありません。確かに、それは一種のテンプレート メタプログラミングのように思えます。これが適切かどうかは、このテンプレートをどのように再利用する予定かによって異なります。

std::vector を使用すると、変数を削除して配列サイズを保持できます。さて、これがあなたのデザインに適しているかどうかはわかりません...テンプレート定義からビニング定義に複雑さが移ります(非常に簡単に初期化できるようになりました)...

最後に、定数を渡してテンプレートをインスタンス化できます。

template < Binning binning, unsigned long N, unsigned long M>
class ... {
     <using N>
}
于 2011-07-19T08:45:56.747 に答える
2

特性クラスを検討しましたか?通常、クラスの動作から分離したい静的情報がある場合は、それをカプセル化するトレイトクラスを作成することを検討してください。

したがって、デフォルトの動作から始めます。

enum Binning {CELL, LARGE, BE};

template <Binning binning>
struct BinTraits
{
    // default behaviour
    int get_bin(double value) { return value / 0.025; } 
};

次に、専門分野を提供します。

const double binning_LARGE[] = {0, 1.2, 1.425, 1.550, 1.800, 2.5};
const double binning_BE[] =  {0, 1.425, 1.550, 2.5};

template <typename RandomAccessCollectionT>
int get_bin_impl(double value, RandomAccessCollectionT collection, unsigned size)
{
    return find_if(collection, collection + size,
           bind2nd(greater<double>(), value)) - collection - 1;
}

template <>
struct BinTraits<LARGE>
{
    int get_bin(double value) { return get_bin_impl(value, binning_LARGE, sizeof(binning_LARGE) / sizeof(binning_LARGE[0])); } 
};

template <>
struct BinTraits<BE>
{
    int get_bin(double value) { return get_bin_impl(value, binning_BE, sizeof(binning_BE) / sizeof(binning_BE[0])); } 
};

次に、実際のコンテナの動作を、ビニング動作を必要とする別のクラスに配置します(これを呼び出しますHashTable)。

template <typename BinTraits>
class HashTable
{
public:
    void insert(double value)
    {
        int bin = BinTraits::get_bin(value);
        _bins[bin].insert(value);
    }
    // _bin is a multimap or something
};
于 2011-07-19T10:16:29.403 に答える
0

ファンクタと同様に and の使用法を見ると、STL といくつかの高度な C++ の概念について十分に理解しているように見えfind_ifます。bind2ndそれでも、あなたがやろうとしていることは、オーバーエンジニアリングのようです。あなたが何をしようとしているのか完全には理解できませんが、テンプレートを完全に廃止して、クラス (異なる値でインスタンス化されたもの) とメソッド パラメーターのみを使用できるようです。

于 2011-07-19T08:42:21.180 に答える