Recently I wrote some experimental code to add operator> for all classes without one. The code is here:
#include <cstdio>
#include <experimental/type_traits>
#include <type_traits>
struct A {
A(int x) : x(x) {}
int x;
bool operator<(const A &rhs) const {
printf("original lt\n");
return x < rhs.x;
}
};
template <class T> using gt_t = decltype(std::declval<T>() > std::declval<T>());
template <class Key>
std::enable_if_t<!std::experimental::is_detected<gt_t, Key>::value, bool>
operator>(const Key &lhs, const Key &rhs) {
printf("generated gt\n");
return rhs < lhs;
}
int main() {
A a(1);
A b(2);
printf("%d\n", b > a);
}
I used "-O2 -std=c++14" to compile, gcc 8.1 and later versions compiled successfully, while gcc 7.5 and older versions generated compile errors ( godbolt link ) like
<source>: In substitution of 'template<class T> using gt_t = decltype ((declval<T>() > declval<T>())) [with T = A]':
<source>:17:18: required by substitution of 'template<class Key> std::enable_if_t<(! typename std::__detector<std::experimental::fundamentals_v2::nonesuch, void, gt_t, Key>::value_t:: value), bool> operator>(const Key&, const Key&) [with Key = A]'
<source>:14:60: required by substitution of 'template<class T> using gt_t = decltype ((declval<T>() > declval<T>())) [with T = A]'
<source>:17:18: required by substitution of 'template<class Key> std::enable_if_t<(! typename std::__detector<std::experimental::fundamentals_v2::nonesuch, void, gt_t, Key>::value_t:: value), bool> operator>(const Key&, const Key&) [with Key = A]'
<source>:14:60: [ skipping 589 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
<source>:17:18: recursively required by substitution of 'template<class _Default, template<class ...> class _Op, class ... _Args> struct std::__detector<_Default, std::__void_t<_Op<_Args ...> >, _Op, _Args ...> [with _Default = std::experimental::fundamentals_v2::nonesuch; _Op = gt_t; _Args = {A}]'
<source>:17:18: required by substitution of 'template<class Key> std::enable_if_t<(! typename std::__detector<std::experimental::fundamentals_v2::nonesuch, void, gt_t, Key>::value_t:: value), bool> operator>(const Key&, const Key&) [with Key = A]'
<source>:17:18: recursively required by substitution of 'template<class _Default, template<class ...> class _Op, class ... _Args> struct std::__detector<_Default, std::__void_t<_Op<_Args ...> >, _Op, _Args ...> [with _Default = std::experimental::fundamentals_v2::nonesuch; _Op = gt_t; _Args = {A}]'
The errors look reasonable to me, because adding operator> for classes that don't have one is somewhat like Russell's paradox. However, compilers like gcc 8.1 and clang 5.0 can actually compile it.
I know there are several methods to solve the original problem (and I already solved it). I just want to know if that code is valid or not, and why different versions of gcc produces different results.