g ++は、“型が期待される私の単純なファンクターを拒否し、「xyz」を取得します”
質問
私はC ++のファンクタで遊んでいます。特に、ペアの最初の要素でソートしたいペアのベクトルを持っています。私は完全に特化したファンクター(つまり、「bool MyLessThan(MyPair& lhs、MyPair& rhs)」のようなもの)を書き始めました。次に、この種のものが興味深いからといって、汎用の「このペアの最初の要素にFを適用する」を書きたいと思いました。ファンクタ。以下を書きましたが、g ++は気に入らないようです。取得:
エラー: 'template struct Pair1stFunc2'のテンプレートパラメーターリストの引数2でのタイプ/値の不一致 エラー:タイプが期待され、「少なく」なりました
#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を改善するためだけに何が起こっているのか知りたいです。
解決
使用している比較タイプでstd :: lessを特殊化する必要があります。
Pair1stFunc2<MyPair, std::less<int> >()
トリックを行います。クラスを直接呼び出すことはできないため、独自のoperator()内で、比較タイプのオブジェクトをインスタンス化する必要もあります。例えば。変更
return F(lhs.first, rhs.first);
to
F func;
return func(lhs.first, rhs.first);
別の答えが示すように、スペシャライゼーションをファンクターに移動することもできます。
他のヒント
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>());
}
動作することに注意してください。ただし、意図したとおりにならない場合があります。
std :: less
はそれ自体がテンプレートであり、 foo()
関数の sortで呼び出すときにテンプレートテンプレートパラメーターを指定しないことに注意してください。
!ここで、 less
は不完全なタイプであるため、問題です。
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
}
最も簡単な解決策は、引数として必要なもの、適切なシグネチャを持つ関数を述べることです:
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はそのようなテンプレートです。その場合、テンプレートテンプレート引数が必要です。