5

less<double>いくつかのコードをリファクタリングしていたところ、セットのコンパレータが1つの場所と別の場所にあることを除いて、同じコードで記述できる場所が2つあることがわかりましたgreater<double>。何かのようなもの:

double MyClass::Function1(double val)
{
    std::set<double, less<double> > s;
    // Do something with s
}

double MyClass::Function2(double val)
{
    std::set<double, greater<double> > s;
    // Do the same thing with s as in Function1
}

だから私はやろうと思った:

double MyClass::GeneralFunction(double val, bool condition)
{  
    if(condition)  
    {  
        // Select greater as comparator  
    }  
    else
    {  
        // Select less as comparator  
    }  

    set<double, comparator> s;  
    // common code
}

次のようなカスタムコンパレータ関数を使用して動作させました。

bool my_greater(double lhs, double rhs)
{
    return lhs > rhs;
}

bool my_less(double lhs, double rhs)
{
    return lhs < rhs;
}

double MyClass::GeneralFunction(double val, bool condition)
{ 
    typedef bool(*Comparator) ( double,  double);
    Comparator comp = &my_less;
    if (condition)
    {
        comp = &my_greater;
    }

    std::set<double, Comparator > s(comp);  

    //....
}

でも内蔵のものを使いたいです。問題は、コンパレータを宣言して組み込み述語を割り当てる方法がわからないことです。

どんな助けでも大歓迎です。

4

4 に答える 4

4

本当にランタイムチェックが必要ですか?

template <class Comp> double MyClass::Function(double val)
{
    std::set<double, Comp > s;
    // Do something with s
}

あなたがそうしても、あなたはまだ使うことができます

double MyClass::Function(double val, bool comp)
{
   return comp ? Function<std::less<double> >(val) : Function<std::greater<double> >(val);
}
于 2012-06-25T07:50:39.913 に答える
4

問題は、調整時にコンパレータのタイプを選択できず、std::less無関係std::greaterなタイプがあることです。同様に、コンパレータとしてstd::setインスタンス化されたは、でインスタンス化されたonとは関係のないタイプを持ちます。考えられる解決策はいくつかありますが、最も単純な(そして、継承、仮想関数、および動的割り当てを含まない唯一の解決策)は、実行している内容に沿ったものです。std::lessstd::greater

class SelectableCompare
{
    bool myIsGreater;
public:
    SelectableCompare( bool isGreater ) : myIsGreater( isGreater ) {}
    bool operator()( double d1, double d2 ) const
    {
        static std::less<double> const less;
        return myIsGreater
            ? less( d2, d1 )
            : less( d1, d2 );
    }
};

私は標準を使用しましたがstd::lessstd::greaterあなたがそうすることに興味を示したからです。の場合double、これは率直に言ってやり過ぎです。私は通常、ただ書いd1 > d2d1 < d2。ただし、一部のタイプには特殊なが含まれている可能性があるため、上記のテンプレートバージョンは理にかなっている場合がありstd::lessます。std::lessこれが私が;だけを使用する理由でもあります 。std::lessプログラマーが専門にしているのは、これが標準ライブラリでの注文に使用される唯一のものであるという知識があることを考えれば、かなり考えられ ます。

完全を期すために:明らかな代替策は、抽象コンパレータベースでコンパレータの戦略パターンを使用することです。

class Comparator
{
public:
    virtual ~Comparator() {}
    virtual bool isLessThan( double d1, double d2 ) const = 0;
};

、さまざまな比較のためのかなり明白な派生クラス、およびメモリを管理するためのラッパー:

class ComparatorWrapper
{
    std::shared_ptr<Comparator> myComparator;
public:
    ComparatorWrapper( Comparator* newed_comparator )
        : myComparator( newed_comparator )
    {
    }
    bool operator()( double d1, double d2 ) const
    {
        return myComparator->isLessThan( d1, d2 );
    }
};

これは、必要なバイナリの選択には間違いなくやり過ぎですが、より多くの選択肢がある場合は適切かもしれません。たとえば、set多くの異なるフィールド(すべて異なるタイプ)の1つでソートされる可能性があります。

于 2012-06-25T08:38:29.333 に答える
3

使用するだけ

std::set<double, std::function<bool(double,double)>>

セットとして、次のようにインスタンス化します。

typedef std::set<double, std::function<bool(double,double)> > RTSet;

RTSet choose_ordering(bool increasing)
{
    if (increasing)
        return RTSet( std::less<double>() );
    else
        return RTSet( std::greater<double>() );
}

一般に、トレードオフは次のいずれかになります。

  • すべての比較で順序を確認する、または
  • インスタンス化時に一度チェックしますが、すべての関数呼び出し(たとえば仮想関数呼び出しなど)で間接参照も発生します

セットの使用中に誤って順序を変更して、そのすべての不変条件を壊さないように、2番目のオプションを使用しています。


これは別の答え(さらには質問)になる可能性があるため、簡単に考えてみてください。ただし、2ビットのコードはソート順を除いて同一であるとおっしゃっています。

いくつかの状況で私が使用した別の方法は、単一のソート方向を使用し、セットで動作するコードを(イテレータータイプごとに)テンプレート化することです。

if (increasing)
    do_stuff(set.begin(), set.end());
else
    do_stuff(set.rbegin(), set.rend());
于 2012-06-25T08:32:59.047 に答える
2

やってみませんか

template <typename Compare>
double MyClass::GeneralFunction(double val)
{
    std::set<double, Compare> s;

    //....
}

正式なパラメータによるテンプレートの選択は、C++がうまく処理できるものではありません。呼び出し元にテンプレート引数を提供させることにより、可能な限りコンパイルフェーズにプッシュします。

次に、実行時にラッパーを本当に選択する場合は、ラッパーを提供できます。

double MyClass::GeneralFunction(double val, bool condition)
{
    return condition ?
        GeneralFunction<std::greater<double> >(val) :
        GeneralFunction<std::less   <double> >(val);\
}
于 2012-06-25T07:49:27.030 に答える