cou*_*age 5 c++ templates language-lawyer
最近,我编写了一些实验代码,为所有没有运算符的类添加运算符>。代码在这里:
#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);
}
Run Code Online (Sandbox Code Playgroud)
我使用“-O2 -std=c++14”进行编译,gcc 8.1及更高版本编译成功,而gcc 7.5及更早版本生成编译错误(godbolt链接),例如
<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}]'
Run Code Online (Sandbox Code Playgroud)
这些错误对我来说看起来很合理,因为为没有运算符> 的类添加运算符有点像罗素悖论。然而,像 gcc 8.1 和 clang 5.0 这样的编译器实际上可以编译它。
我知道有几种方法可以解决原来的问题(而且我已经解决了)。我只是想知道该代码是否有效,以及为什么不同版本的 gcc 会产生不同的结果。