特定积分常数的重载比较

Overloading comparison for specific integral constants

本文关键字:重载 比较 常数      更新时间:2023-10-16

我正在将一大组地理空间代码从一个投影转换到另一个投影。为了在转换过程中强制使用正确的单位,我引入了"距离"、"点"、"矩形"answers"多边形"模板,这些模板带有一个标记,指示使用的坐标系。这是相当好的,但在很多地方对非零(!= 0)或正值(> 0)进行检查。我希望能够重载这些运算符,以便在不与任何其他数字进行比较的情况下与0进行比较。有可能做到这一点吗?

作为一个额外的限制,我不能使用constexpr,因为我必须支持VS 2013,但我仍然很想知道是否有办法使用constexpr

仅供参考,我正在使用这样的东西:

template<typename Tag> struct Distance
{
  int value;
};
template<typename Tag> struct Point
{
  Distance<Tag> x;
  Distance<Tag> y;
};
// This works fine for comparing two Distances
template<typename Tag> bool operator>(const Distance<Tag>& a, const Distance<Tag>& b) {return a.value > b.value;}
// But I don't want this to allow a > 14, only a > 0
template<typename Tag> bool operator>(const Distance<Tag>& a, int b) {return a.value > b;}
struct Mercator;
typedef Point<Mercator> MercPoint;
struct GuiScale;
typedef Point<GuiScale> GuiPoint;
// etc.

您可以使用nullptr_t作为破解(作为文字0转换为nullptr):

template<typename Tag> bool operator>(const Distance<Tag>& a, std::nullptr_t b) {return a.value > 0;}

您可以使用对文字零的任何指针的转换:

#include <type_traits>
template<typename Tag>
struct Distance
{
private:
    using literal_zero = void(Distance::*)();
    template<typename U>
    using enable_nullptr = typename std::enable_if<
        std::is_same< typename std::decay< U >::type, std::nullptr_t >::value
    >::type;
public:
    int value;
    bool operator<( literal_zero ) const { return value < 0; }
    template<typename U>
    enable_nullptr<U> operator<( const U& ) const = delete;
};
int main() {
    Distance<int> a;
    a.value = 0;
    a < 0;
    // a < 42; // does not compile
    // a < nullptr; // does not compile
}

与其他答案不同,这也不允许a < nullptr。此外,如果删除与nullptr相关的部分,并用typedef替换using literal_zero = ...,那么C++98也可以使用相同的技术。

实时示例

如果与文字0进行比较在语义上是有效的,那么允许从文字0进行转换也是有效的。转换到位后,您无需进行特殊情况比较(Coliru Live):

template<typename Tag> struct Distance
{
  int value;
  Distance() = default;
  explicit constexpr Distance(int v) : value(v) {}
  constexpr Distance(std::nullptr_t) : value(0) {}
  friend constexpr bool operator == (const Distance& lhs, const Distance& rhs) {
    return lhs.value == rhs.value;
  }
  friend constexpr bool operator < (const Distance& lhs, const Distance& rhs) {
    return lhs.value < rhs.value;
  }
  // ...
};