Reputation: 139
I am trying to understand new c++ features and I came up with my implementation of max function:
#include <utility>
template <typename T>
concept bool Comparable() {
return requires(T a, T b)
{
{a > b} -> bool;
{a < b} -> bool;
{a >= b} -> bool;
{a <= b} -> bool;
};
}
template<Comparable T, Comparable U>
constexpr decltype(auto) max(T&& a, U&& b)
{
return std::forward<T>(a) > std::forward<U>(b) ? std::forward<T>(a) : std::forward<U>(b);
}
int main()
{
constexpr int a = 2, b = 3;
return max(a, b);
}
Can this replace the macro version?
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
And if not what can be improved?
I am compiling with gcc-8.1.0
and -std=c++2a
, -fconcepts
and -O3
flags
Thank you for your suggestions, this is how it looks now:
#include <utility>
template<typename T, typename U>
concept bool TypesLessComparable() {
return requires(T a, U b)
{
{a < b} -> bool;
};
}
template<typename T, typename U>
constexpr decltype(auto) max(T&& a, U&& b) requires (TypesLessComparable<T, U>() == true)
{
return a < b ? std::forward<U>(b) : std::forward<T>(a);
}
int main()
{
constexpr int a = 2, b = 3;
return max(a, b);
}
Upvotes: 0
Views: 98
Reputation: 44278
Is this max function decent?
No, there are at least 3 issues:
1 Unclear why you request multiple comparison operations when your function only requires one of them (it should be fine for a class
only to define operator>
when only max()
is used)
2 Concept Comparable
requires that type has comparison operations on itself, you may compare 2 object of different types. This invalidates usage of concepts (a function should use only what required/provided by concepts)
3 You may return objects of different types as well, one may convert to another but you should cover that by another concept.
Here is code example for case 2 and 3:
struct A { friend bool operator>( const A&, const A& ); };
struct B { friend bool operator>( const B&, const B& ); };
auto x = max( A(), B() );
To summarize:
Your function should require minimum set of operations on type(s), necessary for it to operate.
If type(s) passed concepts validation your function should compile successfully.
This is most probably not full set of requirements.
Upvotes: 3
Reputation: 238461
std::forward<T>(a) > std::forward<U>(b) ? std::forward<T>(a) : std::forward<U>(b);
You forward the result twice. This is wrong for most types (only OK for types that implement move as a deep copy). You should remove forward from the comparison.
Upvotes: 3