2014-11-07 3 views
1

Я собираюсь преобразовать большой набор геопространственного кода из одного проектора в другой. Чтобы обеспечить соблюдение правильных единиц во время этого преобразования, я ввел шаблоны Distance, Point, Rectangle и Polygon, которые берут тег, указывающий, какая система координат используется. Это работает довольно хорошо, но есть много мест, где проверки выполняются для ненулевого (!= 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. 
+1

Почему не имеют BOOL функции, такие как 'IsZero'? На мой взгляд, перегрузка математических операторов, которые принимают только одно допустимое значение, - плохая идея. –

+0

В чем смысл шаблона класса «Расстояние»? – P0W

+0

@ P0W, поэтому вы не можете дать два несвязанных расстояния 'operator>' (или другую функцию) и дать целочисленному типу имя, соответствующее его использованию. – chris

ответ

2

Вы можете использовать nullptr_t как хак (как буквального 0 преобразовать в nullptr):

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

Я не думал об этом обращении. Это похоже на путь. Благодаря! –

2

Вы можете использовать преобразование-to-any-указатель буквального нуля:

#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

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

Чтобы быть понятным, [это правильно компилируется в MSVC с появлением 'constexpr' stripped] (http://rextester.com/GNLJ4961). – Casey

Смежные вопросы