我希望可以根据当前编译器版本和命令行选项的支持情况,在我的代码中有条件地启用 operator <=>
重载。例如,我希望以下代码在 C++14、17 和 20 下编译通过(这实质上是对我之前提出的问题的解决方案的续篇):
#define SPACESHIP_OPERATOR_IS_SUPPORTED 1 // <--- i want this to be automatic
#if SPACESHIP_OPERATOR_IS_SUPPORTED
#include <compare>
#endif
template <int N> struct thing {
// assume an implicit conversion to a "math-able" type exists:
operator int () const { return 0; }
// define a set of comparison operators for same N on rhs:
bool operator == (const thing<N> &) const { return true; }
bool operator != (const thing<N> &) const { return false; }
bool operator < (const thing<N> &) const { return false; }
bool operator > (const thing<N> &) const { return false; }
bool operator <= (const thing<N> &) const { return true; }
bool operator >= (const thing<N> &) const { return true; }
int operator - (const thing<N> &) const { return 0; }
// but explicitly delete ops for different N:
// (see https://dev59.com/Hb7pa4cB1Zd3GeqP58mG)
template <int R> bool operator == (const thing<R> &) const = delete;
template <int R> bool operator != (const thing<R> &) const = delete;
template <int R> bool operator < (const thing<R> &) const = delete;
template <int R> bool operator > (const thing<R> &) const = delete;
template <int R> bool operator <= (const thing<R> &) const = delete;
template <int R> bool operator >= (const thing<R> &) const = delete;
template <int R> int operator - (const thing<R> &) const = delete;
// but if i don't delete <=> for differing template parameters then things
// like thing<0>() <=> thing<1>() will be allowed to compile because they'll
// be implicitly converted to an int. so i *have* to delete it when supported.
#if SPACESHIP_OPERATOR_IS_SUPPORTED
std::strong_ordering operator <=> (const thing<N> &) const = default;
template <int R> std::strong_ordering operator <=> (const thing<R> &) const = delete;
#endif
};
int main () {
thing<0> t0;
thing<1> t1;
(void)(t0 == t0); // line 39
//(void)(t0 == t1); // line 40
#if SPACESHIP_OPERATOR_IS_SUPPORTED
(void)(t0 <=> t0); // line 42
//(void)(t0 <=> t1); // line 43
#endif
}
首先,快速解释一下:
- 隐式
operator int
是一个要求。 - 仅对具有相同
N
的thing<int N>
定义比较运算符。 - 必须显式删除不匹配的
N
的运算符,否则编译器将决定隐式地将operator int
应用于两侧并使用int
比较而不是想要的行为(请参见链接问题)。 - 预期行为是40和43行(标记)无法编译。
现在,我认为我需要有条件地检查operator <=>
支持的原因是:
- 代码需要作为C++14、17和20进行编译。
- 如果我根本没有重载
<=>
,那么像thing<0>() <=> thing<1>()
这样的东西会被错误地允许编译(由于隐式转换为int
;与其他运算符相同的情况)。换句话说:默认的operator <=>
并不适用于所有情况,因此我不能让它保持原样。 - 如果我总是编写两个
<=>
重载,则程序无法在C++14和C++17上编译,或者可能在具有不完整的C++20实现的编译器上失败(尽管我没有遇到过这种情况)。
上面的代码只要我手动设置SPACESHIP_OPERATOR_IS_SUPPORTED
就可以满足所有要求,但我希望自动化。
那么,我的问题是:有没有办法在编译时检测支持operator <=>
,并在存在时有条件地启用代码?或者还有其他方法使其在C++14到20上工作吗?
我在预编译器的思维模式,但如果有某些神奇的模板解决方案,那也可以。我真的希望有一个与编译器无关的解决方案,但至少我希望它能在GCC(5.x及更高版本)和MSVC(理想情况下是2015及更高版本)上运行。
!=
依赖于==
的行为也存在吗?或者您认为在 17->20 过渡期间存在一些编译器版本具有其中一个特性而不具备另一个特性吗? - Jason C201907
,是的。 - Barry<=>
这个主题,有没有特别的原因要检查 201907 而不是 201711?201711 引用了 P0768R1,而 201907 引用了 P1614R2。虽然我不知道__cpp_impl
版本的宏的重要性,但该宏的版本也可以追溯到 201711。我在解释推荐文档方面遇到了麻烦。 - Jason C<=>
的设计在标准化过程中发生了很大的变化,因此只需选择最新的版本即可。 - Barry