特定积分常数的重载比较

时间:2014-11-07 15:53:12

标签: c++ templates c++11

我正在将大量地理空间代码从一个投影转换为另一个投影。为了在此转换期间强制执行适当的单位,我引入了距离,点,矩形和多边形模板,这些模板采用标记来指示使用的坐标系。这样做效果很好,但是有很多地方会对非零(!= 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.

3 个答案:

答案 0 :(得分:2)

您可以将nullptr_t用作黑客(将文字0转换为nullptr):

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

答案 1 :(得分:2)

您可以使用字面零的转换为任意指针:

#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相关部分并将using literal_zero = ...替换为typedef,则相同的技巧也适用于C ++ 98。

Live example

答案 2 :(得分:1)

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

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;
  }
  // ...
};