
Omry Jadan
Ich versuche, die Standardreihenfolge der Elemente in einer Reihe von Ganzzahlen so zu ändern, dass sie lexikographisch statt numerisch sind, und ich kann Folgendes nicht mit g++ kompilieren:
Datei.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);
...
}
Ich bekomme folgenden Fehler:
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’
Was mache ich falsch?

diralik
1. Moderne C++20-Lösung
auto cmp = [](int a, int b) { return ... };
std::set<int, decltype(cmp)> s;
Wir verwenden die Lambda-Funktion als Komparator. Wie üblich sollte comparator einen booleschen Wert zurückgeben, der angibt, ob das als erstes Argument übergebene Element als vor dem zweiten in der Spezifizierung betrachtet wird strikte schwache Ordnung es definiert.
Online-Demo
2. Moderne C++11-Lösung
auto cmp = [](int a, int b) { return ... };
std::set<int, decltype(cmp)> s(cmp);
Vor C++20 müssen wir Lambda als Argument an den Set-Konstruktor übergeben
Online-Demo
3. Ähnlich der ersten Lösung, aber mit Funktion statt Lambda
Komparator als übliche boolesche Funktion erstellen
bool cmp(int a, int b) {
return ...;
}
Dann verwenden Sie es entweder auf diese Weise:
std::set<int, decltype(cmp)*> s(cmp);
Online-Demo
oder so:
std::set<int, decltype(&cmp)> s(&cmp);
Online-Demo
4. Alte Lösung mit struct with ()
Operator
struct cmp {
bool operator() (int a, int b) const {
return ...
}
};
// ...
// later
std::set<int, cmp> s;
Online-Demo
5. Alternative Lösung: Struktur aus boolescher Funktion erstellen
Nehmen Sie die boolesche Funktion
bool cmp(int a, int b) {
return ...;
}
Und struct daraus machen mit std::integral_constant
#include <type_traits>
using Cmp = std::integral_constant<decltype(&cmp), &cmp>;
Verwenden Sie schließlich die Struktur als Komparator
std::set<X, Cmp> set;
Online-Demo

Yacoby
Sie verwenden eine Funktion, wo Sie einen Funktor verwenden sollten (eine Klasse, die den ()-Operator überlädt, damit sie wie eine Funktion aufgerufen werden kann).
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();
}
};
Sie verwenden dann den Klassennamen als Typparameter
set<int64_t, lex_compare> s;
Wenn Sie den Funktor-Boilerplate-Code vermeiden möchten, können Sie auch einen Funktionszeiger verwenden (vorausgesetzt lex_compare
ist eine Funktion).
set<int64_t, bool(*)(const int64_t& lhs, const int64_t& rhs)> s(&lex_compare);
Die Antwort von Yacoby inspiriert mich, einen Adapter zum Kapseln der Funktor-Boilerplate zu schreiben.
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!
Wow, ich glaube, das war die Mühe wert!
Sie können einen Funktionskomparator verwenden, ohne ihn wie folgt zu umbrechen:
bool comparator(const MyType &lhs, const MyType &rhs)
{
return [...];
}
std::set<MyType, bool(*)(const MyType&, const MyType&)> mySet(&comparator);
Dies ist irritierend, wenn Sie jedes Mal ein Set dieses Typs benötigen, und kann Probleme verursachen, wenn Sie nicht alle Sets mit demselben Komparator erstellen.

Ciro Santilli Путлер Капут 六四事
std::less<>
bei der Verwendung von benutzerdefinierten Klassen mit operator<
Wenn Sie es mit einem Satz Ihrer benutzerdefinierten Klasse zu tun haben operator<
definiert, dann können Sie einfach verwenden std::less<>
.
Wie unter erwähnt http://en.cppreference.com/w/cpp/container/set/find C++14 hat zwei neue hinzugefügt find
APIs:
template< class K > iterator find( const K& x );
template< class K > const_iterator find( const K& x ) const;
die es Ihnen ermöglichen:
main.cpp
#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);
}
Kompilieren und ausführen:
g++ -std=c++14 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out
Mehr Infos zu std::less<>
finden Sie unter: Was sind transparente Komparatoren?
Getestet auf Ubuntu 16.10, g++
6.2.0.
9934600cookie-checkVerwenden des benutzerdefinierten std::set-Komparatorsyes