6

私はC++でファンクターをいじっています。特に、ペアの最初の要素でソートしたいペアのベクトルがあります。私は完全に特殊化されたファンクター (つまり、"bool MyLessThan(MyPair &lhs, MyPair &rhs)" のようなもの) を書き始めました。次に、この種のものが興味深いという理由だけで、一般的な「このペアの最初の要素に F を適用する」ファンクターを書いてみたかったのです。以下に書いたのですが、g++ が苦手です。私は得る:

エラー: 'template struct Pair1stFunc2' のテンプレート パラメーター リストの引数 2 で型/値が一致しません エラー: 型が必要ですが、'less' が得られました

#include <algorithm>
#include <functional>
#include <utility>
#include <vector>

template <class P, class F>
struct Pair1stFunc2
{
    typename F::result_type operator()(P &lhs, P &rhs) const
    { return F(lhs.first, rhs.first); }

    typename F::result_type operator()(const P &lhs, const P &rhs) const
    { return F(lhs.first, rhs.first); }
};

typedef std::pair<int,int> MyPair;
typedef std::vector<MyPair> MyPairList;

MyPairList pairs;

void foo(void)
{
    std::sort(pairs.begin(),
              pairs.end(),
              Pair1stFunc2<MyPair, std::less>());
}

ここで私が間違っていることに誰かが光を当てることができますか? これは少し人為的な例であることはわかっていますが、STL-fu を改善するためだけに、何が起こっているのか知りたいです。

4

5 に答える 5

6

dirkgently の回答を拡張するために、意図したとおりに機能する例を次に示します。

template <typename T, template <typename> class F>
struct Pair1stFunc2
{
    template <typename P>
    typename F<T>::result_type operator()(P &lhs, P &rhs) const
    { F<T> f; return f(lhs.first, rhs.first); }

    template <typename P>
    typename F<T>::result_type operator()(const P &lhs, const P &rhs) const
    { F<T> f; return f(lhs.first, rhs.first); }
};

void foo(void)
{
    std::sort(pairs.begin(),
              pairs.end(),
              Pair1stFunc2<int, std::less>());
}

動作しますが、意図したとおりではない可能性があることに注意してください。

于 2009-05-05T14:22:30.550 に答える
3

これはそれ自体がテンプレートであり、関数の!std::lessを使用して呼び出すときにテンプレートテンプレートパラメータを指定しないことに注意してください。これは不完全なタイプであるため、問題があります。foo()sortless

于 2009-05-05T14:13:17.920 に答える
2

使用している比較タイプでstd::lessを特殊化する必要があります。

Pair1stFunc2<MyPair, std::less<int> >()

トリックを行います。クラスを直接呼び出すことはできないため、独自のoperator()内で、比較タイプのオブジェクトをインスタンス化する必要もあります。例:変更

return F(lhs.first, rhs.first);

F func;
return func(lhs.first, rhs.first);

別の回答が示唆するように、スペシャライゼーションをファンクターに移動することもできます。

于 2009-05-05T14:19:28.703 に答える
2

unwesen に似ています。ただし、テンプレート テンプレートを使用する必要はありません。

#include <algorithm>
#include <functional>
#include <memory>
#include <vector>

typedef std::pair<int,int> MyPair;
typedef std::vector<MyPair> MyPairList;
MyPairList pairs;


// Same as original.
template <typename T,typename F>
struct Pair1stFunc2
{
    template <typename P>
    typename F::result_type operator()(P &lhs, P &rhs) const
    { F f;  // Just need to create an anstance of the functor to use.
      return f(lhs.first, rhs.first); }

    template <typename P>
    typename F::result_type operator()(const P &lhs, const P &rhs) const
    { F f;  // Just need to create an anstance of the functor to use.
      return f(lhs.first, rhs.first); }
};


void foo(void)
{
    std::sort(pairs.begin(),
              pairs.end(),
              Pair1stFunc2<int, std::less<int> >()); // initialize the version of less
}
于 2009-05-05T15:13:35.857 に答える
1

最も簡単な解決策は、引数として必要なもの、つまり適切なシグネチャを持つ関数を記述することです。

template<typename P, bool (*F)(P,P)> struct Pair1stFunc2 { ... }

この場合、関数テンプレートを 2 番目の引数として渡すと、引数の型として P,P を使用してオーバーロードの解決が行われます。これは、オーバーロードの解像度を外に移動するために機能しますstruct Pair1stFunc2::operator()

functorを渡す可能性も必要ですが、それらはテンプレート型引数として渡され、 operator() 内で作成される必要があります。

typename F::result_type operator()(const P &lhs, const P &rhs) const
{ return F()(lhs.first, rhs.first); }

ここで、F はファンクターの型で、F() はそのファンクターのインスタンスです。

3 番目のケースは、すでに以前にカバーされている、ファンクター テンプレートです。std::less はそのようなテンプレートです。その場合、テンプレート テンプレート引数が必要です。

于 2009-05-05T14:40:56.263 に答える