10

関数オブジェクトと関数ポインタに関する 2 つの質問があります。


質問1

STLのさまざまな用途のアルゴリズムを読むsortと、3 番目のパラメーターが関数オブジェクトになる可能性があることがわかります。以下に例を示します。

class State {  
  public:  
    //...
    int population() const;  
    float aveTempF() const;  
    //...  
};    
struct PopLess : public std::binary_function<State,State,bool> {  
    bool operator ()( const State &a, const State &b ) const  
        { return popLess( a, b ); }  
};  
sort( union, union+50, PopLess() );  

質問 :

さて、ステートメントはどのように機能しsort(union, union+50,PopLess())ますか? 一時オブジェクトで関数を実行するのと同じPopLess()ようなものに解決する必要があります。これは、 (私の例のように)オーバーロードされた操作の戻り値をアルゴリズムに渡すことだと思います。PopLess tempObject.operator()operator ()boolsort

では、この場合、並べ替え関数はどのように 3 番目のパラメーターを解決しますか?


質問2

質問

関数オブジェクトを使用することと、関数ポインターを使用することには、何か特別な利点がありますか? 以下の関数ポインターを使用すると、不利な点が導き出されますか?

inline bool popLess( const State &a, const State &b )
    { return a.population() < b.population(); }  
std::sort( union, union+50, popLess ); // sort by population

PS : 上記の両方の参照 (例を含む) は、"Stephen C. Dewhurst" による書籍 "C++ Common Knowledge: Essential Intermediate Programming" からのものです。
トピックの内容を解読できなかったため、ヘルプを投稿しました。

よろしくお願いします。

4

6 に答える 6

8

PopLess()PopLessに渡されるクラスの一時インスタンスをインスタンス化しますstd::sort()。これは、次のように言うのと事実上同じです (この例では、余分なコピーが作成されることに注意してください)。

PopLess pl = PopLess();
sort(union, union + 60, pl);

次に、そのインスタンスでstd::sort()を呼び出します。operator()

関数オブジェクトと関数ポインターのどちらが「優れている」かについては、状況によって異なります。おそらく最も重要な違いは、ポインターによって渡される通常の関数は状態を維持できないのに対し、関数オブジェクトは状態を維持できることです。コンパイラは、どちらか一方をより適切に最適化できる場合がありますが、ほとんどの使用シナリオでは、おそらく重要ではありません。

于 2010-06-09T01:04:57.100 に答える
5

質問1:

PopLess()PopLess > tempObject.operator()一時オブジェクトで operator () 関数を実行するのと同じようなものに解決する必要があります。

[あなたが言ったように拡張] ではありません。実際には、暗黙のコンストラクターPopLess()への呼び出しです。PopLess::PopLess()このコードは一時オブジェクトを作成し、それを関数呼び出しの 3 番目のパラメーターに渡します。

質問2

関数オブジェクトを使用することと、関数ポインターを使用することには、何か特別な利点がありますか?

この場合ではありません。ここで、PopLess オブジェクトはステートレスです。内部状態を持つファンクター (関数オブジェクト) を作成できます。

例:

struct ensure_min
{
    int value;
    ensure_min(int val) : value(val) {}
    int operator()(const int& i)
    {
        return std::max(value, i);
    }
}

std::vector<int>  values;
values.push_back(-1);
values.push_back(0);
values.push_back(1);
values.push_back(2);
values.push_back(3);

std::transform(values.begin(), values.end(), 
    std::ostream_iterator<int>(std::cout, "\n"), ensure_min(1));

このコードは、シーケンス内のすべての数値を出力し、出力内のすべての数値の最小値が 1 になるようにします (出力は、元の数値がそれより小さい場合は 1、または元の数値がより大きい場合は元の数値のいずれかになります)。または 1 に等しい)。

于 2010-06-09T08:39:04.790 に答える
3

Q1:PopLess()型のオブジェクトを作成し、このオブジェクトPopLesssort使用して範囲内の要素をoperator ().

関数を見るfor_each方が簡単かもしれませんが、次のように実装できます。

template <typename IterT, typename Function>
Function for_each( IterT first, IterT last, Function f ) {
    for( ; first != last; ++first )
        f(*first);

    return f;
}

したがって、基本的にfor_eachsort、および関数オブジェクトを使用する関数は、単に関数オブジェクトのインスタンスを取得し、その を呼び出しますoperator ()

Q2: 関数ポインターではなく関数オブジェクトを使用している場合、コンパイラーはインライン化によって関数呼び出しを最適化できる場合があります。これは、コンパイラーが関数ポインターを処理するほど単純ではない可能性があります。また、関数オブジェクトは状態を持つことができます。

于 2010-06-09T01:08:16.413 に答える
2

質問 1 が何を求めているのかわかりませんが、PopLess() はオブジェクトです。sort 関数内で、このオブジェクトには項目を比較するために呼び出される operator() メソッドがあります。

于 2010-06-09T01:05:21.660 に答える
0

実際の主な違いは、ファンクタが状態を維持できることです。たとえば、複数列のデータをソートする場合、ファンクターはソートする列、ソート方向、さらには照合ルール (大文字と小文字の区別など) に関する情報を取得できます。

于 2010-06-12T17:01:26.697 に答える
0
  • 質問 1: PopLess() は一時オブジェクトです。
  • 質問2:「関数」に状態を持たせることができます...関数として使用される前に、好きなものでオブジェクトを初期化できます
于 2010-06-09T01:05:13.470 に答える