整数のセット内のアイテムのデフォルトの順序を数値ではなく辞書式に変更しようとしていますが、g ++でコンパイルするために次のものを取得できません。
file.cpp:
bool Lex_compare(const int64_t &a, const int64_t &b)
{
stringstream s1,s2;
s1 << a;
s2 << b;
return s1.str() < s2.str();
}
void foo()
{
set<int64_t, Lex_compare> s;
s.insert(1);
...
}
次のエラーが表示されます。
error: type/value mismatch at argument 2 in template parameter list for ‘template<class _Key, class _Compare, class _Alloc> class std::set’
error: expected a type, got ‘Lex_compare’
私は何を間違えていますか?
ファンクタ(()演算子をオーバーロードしてクラスを関数のように呼び出すことができるクラス)を使用する必要がある関数を使用しています。
struct Lex_compare {
bool operator() (const int64_t& lhs, const int64_t& rhs) const {
stringstream s1, s2;
s1 << lhs;
s2 << rhs;
return s1.str() < s2.str();
}
};
次に、クラス名をtypeパラメーターとして使用します
set<int64_t, Lex_compare> s;
ファンクターボイラープレートコードを回避する場合は、関数ポインターを使用することもできます(Lex_compare
が関数であると仮定)。
set<int64_t, bool(*)(const int64_t& lhs, const int64_t& rhs)> s(&Lex_compare);
auto cmp = [](int a, int b) { return ... };
std::set<int, decltype(cmp)> s(cmp);
lambda function をコンパレータとして使用します。通常どおり、コンパレータはブール値を返す必要があり、最初の引数として渡された要素が特定の strict weak ordering で2番目の引数の前にあると見なされるかどうかを示します。
コンパレータを通常のブール関数として作成します
bool cmp(int a, int b) {
return ...;
}
次にそれを使用する
std::set<int, decltype(&cmp)> s(&cmp);
()
演算子でstructを使用する古いソリューションstruct cmp {
bool operator() (int a, int b) const {
return ...
}
};
// ...
// later
std::set<int, cmp> s;
ブール関数を取る
bool cmp(int a, int b) {
return ...;
}
そして、 std::integral_constant
を使用してそれから構造体を作成します
#include <type_traits>
using Cmp = std::integral_constant<decltype(&cmp), &cmp>;
最後に、構造体をコンパレータとして使用します
std::set<X, Cmp> set;
Yacobyの答えは、ファンクターボイラープレートをカプセル化するためのアダプターを書くように私を刺激します。
template< class T, bool (*comp)( T const &, T const & ) >
class set_funcomp {
struct ftor {
bool operator()( T const &l, T const &r )
{ return comp( l, r ); }
};
public:
typedef std::set< T, ftor > t;
};
// usage
bool my_comparison( foo const &l, foo const &r );
set_funcomp< foo, my_comparison >::t boo; // just the way you want it!
うわー、それはトラブルの価値があったと思います!
次のようにラップせずに関数コンパレーターを使用できます。
bool comparator(const MyType &lhs, const MyType &rhs)
{
return [...];
}
std::set<MyType, bool(*)(const MyType&, const MyType&)> mySet(&comparator);
そのタイプのセットが必要になるたびにタイプアウトするのはイライラし、同じコンパレータですべてのセットを作成しないと問題が発生する可能性があります。
std::less<>
operator<
でカスタムクラスを使用する場合
operator<
が定義されているカスタムクラスのセットを扱っている場合は、次のようにstd::less<>
を使用できます。
http://en.cppreference.com/w/cpp/container/set/find で述べたように、C++ 14は2つの新しいfind
APIを追加しました。
template< class K > iterator find( const K& x );
template< class K > const_iterator find( const K& x ) const;
これにより、次のことが可能になります。
#include <cassert>
#include <set>
class Point {
public:
// Note that there is _no_ conversion constructor,
// everything is done at the template level without
// intermediate object creation.
//Point(int x) : x(x) {}
Point(int x, int y) : x(x), y(y) {}
int x;
int y;
};
bool operator<(const Point& c, int x) { return c.x < x; }
bool operator<(int x, const Point& c) { return x < c.x; }
bool operator<(const Point& c, const Point& d) {
return c.x < d;
}
int main() {
std::set<Point, std::less<>> s;
s.insert(Point(1, -1));
s.insert(Point(2, -2));
s.insert(Point(0, 0));
s.insert(Point(3, -3));
assert(s.find(0)->y == 0);
assert(s.find(1)->y == -1);
assert(s.find(2)->y == -2);
assert(s.find(3)->y == -3);
// Ignore 1234, find 1.
assert(s.find(Point(1, 1234))->y == -1);
}
Ubuntu 16.10、g++
6.2.0でテスト済み:
g++ -std=c++14 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out
std::less<>
の詳細については、次を参照してください。 透明なコンパレータとは?