Moje rozwiązanie jest wszystko w klasie:
struct FooComp {
using is_transparent = std::true_type;
struct FooProj {
std::string const& str;
FooProj(std::string const& sin):str(sin) {}
FooProj(const Foo& foo):str(foo.id) {}
FooProj(FooProj const&) = default;
friend bool operator<(FooProj lhs, FooProj rhs) {
return lhs.str < rhs.str;
}
};
bool operator()(FooProj lhs, FooProj rhs) const
{
return lhs<rhs;
}
};
To nie jest suppor typy, które można przekonwertować na std::string
.
Jednak, gdy robi porównanie projekcji opartej zrobić to:
template<class F, class After=std::less<>>
auto order_by(F&& f, After&& after={}) {
return
[f=std::forward<F>(f), after=std::forward<After>(after)]
(auto&& rhs, auto&&lhs)->bool {
return after(f(decltype(lhs)(lhs)), f(decltype(rhs)(rhs)));
};
}
która odbywa projekcję i generuje funkcję porównawczą dla niego. Robimy to przezroczysty z:
template<class F>
struct as_transparent_t {
F f;
using is_transparent=std::true_type;
template<class Lhs, class Rhs>
bool operator(Lhs const& lhs, Rhs const& rhs)const{ return f(lhs, rhs); }
};
template<class F>
as_transparent_f<std::decay_t<F>>
as_transparent(F&& f) { return {std::forward<F>(f)}; }
więc możemy wystawać i być przejrzysty poprzez:
as_transparent(order_by(some_projection));
których tylko pozostawia projekcji.
w C++ 14 po prostu zrobić
std::string const& foo_proj_f(std::string const& str) { return str; }
std::string const& foo_proj_f(Foo const& foo) { return foo.id; }
auto foo_proj = [](auto const& x)->decltype(auto){ return foo_proj_f(x); };
auto foo_order = as_transparent(order_by(foo_proj));
który łamie rzeczy w dół na kawałki modułowych.
w C++ 17 możemy użyć if constexpr
:
auto foo_proj = [](auto const& x)->std::string const& {
if constexpr(std::is_same<decltype(x), std::string const&>{}) {
return x;
}
if constexpr(std::is_same<decltype(x), Foo const&>{}) {
return x.id;
}
};
auto foo_order = as_transparent(order_by(foo_proj));
lub
template<class...Ts>
struct overloaded:Ts...{
using Ts::operator()...;
overloaded(Ts...ts):Ts(std::move(ts)...){}
};
template<class...Ts> overloaded -> overloaded<Ts...>;
który pozwala
auto foo_proj = overloaded{
[](std::string const& s)->decltype(auto){return s;},
[](Foo const& f)->decltype(auto){return f.id;}
};
które mogą być łatwiejsze do odczytania niż wersja if constexpr
. (Ta wersja może być również dostosowana do c++14 lub c++11).
przy użyciu szablonu? (tylko losowe domysły :) – user1810087
@Slava Wystarczy zadeklarować konstruktor konwersji dla struktury. –
@VladfromMoscow ale to miałoby narzut na niebanalną strukturę 'Foo' prawda? To nie jest dokładnie takie samo rozwiązanie.Oczywiście nie oznacza to, że nie jest to jedno z rozwiązań. Prawdopodobnie powinieneś to zrobić. – Slava