snippetcppMinor
C++ vectors sort ascending/descending
Viewed 0 times
sortvectorsascendingdescending
Problem
How can I eliminate repetition from this code?
I tried
but it fails because
Another question: is it possible to automatically retrieve the required type,
std::vector vec;
bool descending;
if (descending)
{
std::sort(vec.begin(),
vec.end(),
std::greater());
}
else
{
std::sort(vec.begin(),
vec.end(),
std::less());
}I tried
std::sort(vec.begin(),
vec.end(),
descending
? std::greater()
: std::less());but it fails because
greater and less do not evaluate to the same type.Another question: is it possible to automatically retrieve the required type,
std::wstring, from the object vec?Solution
There are a few ways of going about this. One is creating an aggregate type that can forward to the call to the correct comparator.
The downside of this is that a
If the decision is always known at compile time, you can play some template tricks:
This requires
This might be a one step forward, two step back kind of solution. It's quite a bit of code to avoid an
Edit: As @LokiAstari pointed out, you can simplify the above with inheritance:
template
struct comp
{
private:
bool desc;
std::greater great;
std::less less;
public:
explicit comp(bool descending = false)
: desc(descending)
{ }
bool operator()(const T& f, const T& g) const
{
return (desc) ? great(f, g) : less(f, g);
}
};The downside of this is that a
comp object will be at least sizeof(greater + less + bool). This may or may not be a problem. Your call to sort would then look something like:typedef std::wstring str_t;
bool descending = true;
std::sort(vec.begin(), vec.end(), comp(descending));If the decision is always known at compile time, you can play some template tricks:
template
struct comp;
template
struct comp
{
private:
std::greater great;
public:
bool operator()(const T& f, const T& g) const
{
return great(f, g);
}
};
template
struct comp
{
private:
std::less less;
public:
bool operator()(const T& f, const T& g) const
{
return less(f, g);
}
};This requires
descending to be const or constexpr:constexpr bool descending = false;
std::sort(v.begin(), v.end(), comp());This might be a one step forward, two step back kind of solution. It's quite a bit of code to avoid an
if/else - you'll need to decide if this is worth it at all.Edit: As @LokiAstari pointed out, you can simplify the above with inheritance:
template
struct comp
: std::greater
{ }
template
struct comp
: std::less
{ }Code Snippets
template <typename T>
struct comp
{
private:
bool desc;
std::greater<T> great;
std::less<T> less;
public:
explicit comp(bool descending = false)
: desc(descending)
{ }
bool operator()(const T& f, const T& g) const
{
return (desc) ? great(f, g) : less(f, g);
}
};typedef std::wstring str_t;
bool descending = true;
std::sort(vec.begin(), vec.end(), comp<str_t>(descending));template <typename T, bool desc>
struct comp;
template <typename T>
struct comp<T, true>
{
private:
std::greater<T> great;
public:
bool operator()(const T& f, const T& g) const
{
return great(f, g);
}
};
template <typename T>
struct comp<T, false>
{
private:
std::less<T> less;
public:
bool operator()(const T& f, const T& g) const
{
return less(f, g);
}
};constexpr bool descending = false;
std::sort(v.begin(), v.end(), comp<str_t, descending>());template <typename T>
struct comp<T, true>
: std::greater<T>
{ }
template <typename T>
struct comp<T, false>
: std::less<T>
{ }Context
StackExchange Code Review Q#26209, answer score: 5
Revisions (0)
No revisions yet.