Implementing chained comparisons by overloading operators












0














In many languages, X <= Y <= Z is equivalent to X <= Y && Y <= Z. This is not so in C++, and g++ produces this warning if we do try to write that:



comparisons like ‘X<=Y<=Z’ do not have their mathematical meaning


So I tried to impement that in C++ (C++11):



(chained_comparisons.h)





#include <utility>
#include <type_traits>


namespace chained_comparisons {
template<class T>
class chained_comparisons;

namespace detail {
template<class T>
struct is_chained_comparison_helper : ::std::false_type::type {};

template<class T>
struct is_chained_comparison_helper<chained_comparisons<T>> : ::std::true_type::type {};

template<class T>
struct is_chained_comparison : is_chained_comparison_helper<typename ::std::remove_cv<typename ::std::remove_reference<T>::type>::type>::type {};

struct chained_comparisons_helper {
template<class T>
constexpr chained_comparisons<T> operator()(T&& of) const noexcept {
return chained_comparisons<T>{ ::std::forward<T>(of) };
}

// Alternative to c(...) is c >> ..., as >> has higher precedence
// than comparison operators, and nothing has to go to the right of the first value.
// And it looks like the rhs is being "imbued" with the ability to chain comparison.
template<class T>
constexpr chained_comparisons<T> operator>>(T&& of) const noexcept {
return chained_comparisons<T>{ ::std::forward<T>(of) };
}

// Provided to silence compilers that warn about precedence in "A >> B < C".
// Use `A * B < C` instead.
template<class T>
constexpr chained_comparisons<T> operator/(T&& of) const noexcept {
return chained_comparisons<T>{ ::std::forward<T>(of) };
}
};
}

// This class holds a reference and whether the comparisons chained so far have
// succeeded. The only way for a comparison with this class to succeed is if
// all previous comparisons have succeeded and comparison with the reference succeeds.
template<class T>
class chained_comparisons {
public:
T&& of;
bool value = true;
explicit constexpr chained_comparisons(T&& of_, bool value_ = true) noexcept : of(::std::forward<T>(of_)), value(value_) {};

// Helper macro that expands DEFINE_CHAINED_COMPARISON_OPERATOR for all comparison operators
#define DEFINE_ALL_CHAINED_COMPARISON_OPERATORS
DEFINE_CHAINED_COMPARISON_OPERATOR(==)
DEFINE_CHAINED_COMPARISON_OPERATOR(!=)
DEFINE_CHAINED_COMPARISON_OPERATOR(>)
DEFINE_CHAINED_COMPARISON_OPERATOR(<)
DEFINE_CHAINED_COMPARISON_OPERATOR(>=)
DEFINE_CHAINED_COMPARISON_OPERATOR(<=)

// Define member functions to chain comparisons (1) generally and (2) with other chained_comparison<U>
#define DEFINE_CHAINED_COMPARISON_OPERATOR(op)
template<class U>
constexpr
chained_comparisons<U> operator op (U&& other) const
noexcept(noexcept(static_cast<bool>(::std::forward<T>(of) op ::std::forward<U>(other)))) {
return chained_comparisons<U>{ ::std::forward<U>(other), value && static_cast<bool>(::std::forward<T>(of) op ::std::forward<U>(other)) };
}

template<class U>
constexpr
chained_comparisons<U> operator op (const chained_comparisons<U>& other) const
noexcept(noexcept(static_cast<bool>(::std::forward<T>(of) op ::std::forward<U>(other.of)))) {
return chained_comparisons<U>{ other.of, value && other.value && static_cast<bool>(::std::forward<T>(of) op ::std::forward<U>(other.of)) };
}

DEFINE_ALL_CHAINED_COMPARISON_OPERATORS

#undef DEFINE_CHAINED_COMPARISON_OPERATOR

// Convert to bool implicitly
constexpr operator bool() const noexcept { return value; }
constexpr bool operator!() const noexcept { return !value; }
};

// Define functions to be able to have the chain_comparison<T> on the right side as well
#define DEFINE_CHAINED_COMPARISON_OPERATOR(op) template<class T, class U>
constexpr
typename ::std::enable_if<!detail::is_chained_comparison<U>::value, chained_comparisons<T>>::type
operator op (U&& other, const chained_comparisons<T>& self)
noexcept(noexcept(static_cast<bool>(::std::forward<U>(other) op ::std::forward<T>(self.of)))) {
return chained_comparisons<T>{ ::std::forward<T>(self.of), self.value && static_cast<bool>(::std::forward<U>(other) op ::std::forward<T>(self.of)) };
}

DEFINE_ALL_CHAINED_COMPARISON_OPERATORS

#undef DEFINE_CHAINED_COMPARISON_OPERATOR
#undef DEFINE_ALL_CHAINED_COMPARISON_OPERATORS

// c is a shorthand helper to begin chained comparisons.
// c >> X <= Y <= Z, c / X <= Y <= Z, or c(X) <= Y <= Z.
static const detail::chained_comparisons_helper c;

}


(test.cpp)



#include "./chained_comparisons.h"

#include <iostream>
#include <ios>
#include <cstddef>

int main() {
using ::chained_comparisons::c;

::std::boolalpha(::std::cout);

// Disable warning produced by X<=Y<=Z
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wparentheses"
// false (((-3 <= -1) < 0) -> ((true) < 0) -> (1 < 0) -> false)
::std::cout << "-3 <= -1 < 0: " << (-3 <= -1 < 0) << 'n';

// Both true
::std::cout << "c(-3) <= -1 < 0: " << (c(-3) <= -1 < 0) << 'n';
::std::cout << "c >> -3 <= -1 < 0: " << (c >> -3 <= -1 < 0) << 'n';
#pragma GCC diagnostic pop
}


I've tried to have perfect forwarding through all the functions (c -> chained_comparison -> operator op), so this could theoretically support a non-const comparison method without making copies (Though this breaks if you don't expect the comparison to be convertible to a bool, which is understandable).



There are two issues I have right now.



First is that I use a lot of macros. But this prevents duplicating code 6 times for all the operators, so I find this understandable. Is there a better way to define the similar functions?



The second issue is that I don't think this is easy to read. I can read it now that I've just written it, but I don't think I'd be able to read it again after some time. Is this because I'm writing something very wierd / uncommon, or am I making a stylistic mistake?



Also, I don't know if this is very practical. I think c >> X <= Y <= Z is clunkier to write than X <= Y && Y <= Z (And more people would know what the second is saying). It compiles to the same thing in the end, which seems to suggest that I forwarded properly.










share|improve this question



























    0














    In many languages, X <= Y <= Z is equivalent to X <= Y && Y <= Z. This is not so in C++, and g++ produces this warning if we do try to write that:



    comparisons like ‘X<=Y<=Z’ do not have their mathematical meaning


    So I tried to impement that in C++ (C++11):



    (chained_comparisons.h)





    #include <utility>
    #include <type_traits>


    namespace chained_comparisons {
    template<class T>
    class chained_comparisons;

    namespace detail {
    template<class T>
    struct is_chained_comparison_helper : ::std::false_type::type {};

    template<class T>
    struct is_chained_comparison_helper<chained_comparisons<T>> : ::std::true_type::type {};

    template<class T>
    struct is_chained_comparison : is_chained_comparison_helper<typename ::std::remove_cv<typename ::std::remove_reference<T>::type>::type>::type {};

    struct chained_comparisons_helper {
    template<class T>
    constexpr chained_comparisons<T> operator()(T&& of) const noexcept {
    return chained_comparisons<T>{ ::std::forward<T>(of) };
    }

    // Alternative to c(...) is c >> ..., as >> has higher precedence
    // than comparison operators, and nothing has to go to the right of the first value.
    // And it looks like the rhs is being "imbued" with the ability to chain comparison.
    template<class T>
    constexpr chained_comparisons<T> operator>>(T&& of) const noexcept {
    return chained_comparisons<T>{ ::std::forward<T>(of) };
    }

    // Provided to silence compilers that warn about precedence in "A >> B < C".
    // Use `A * B < C` instead.
    template<class T>
    constexpr chained_comparisons<T> operator/(T&& of) const noexcept {
    return chained_comparisons<T>{ ::std::forward<T>(of) };
    }
    };
    }

    // This class holds a reference and whether the comparisons chained so far have
    // succeeded. The only way for a comparison with this class to succeed is if
    // all previous comparisons have succeeded and comparison with the reference succeeds.
    template<class T>
    class chained_comparisons {
    public:
    T&& of;
    bool value = true;
    explicit constexpr chained_comparisons(T&& of_, bool value_ = true) noexcept : of(::std::forward<T>(of_)), value(value_) {};

    // Helper macro that expands DEFINE_CHAINED_COMPARISON_OPERATOR for all comparison operators
    #define DEFINE_ALL_CHAINED_COMPARISON_OPERATORS
    DEFINE_CHAINED_COMPARISON_OPERATOR(==)
    DEFINE_CHAINED_COMPARISON_OPERATOR(!=)
    DEFINE_CHAINED_COMPARISON_OPERATOR(>)
    DEFINE_CHAINED_COMPARISON_OPERATOR(<)
    DEFINE_CHAINED_COMPARISON_OPERATOR(>=)
    DEFINE_CHAINED_COMPARISON_OPERATOR(<=)

    // Define member functions to chain comparisons (1) generally and (2) with other chained_comparison<U>
    #define DEFINE_CHAINED_COMPARISON_OPERATOR(op)
    template<class U>
    constexpr
    chained_comparisons<U> operator op (U&& other) const
    noexcept(noexcept(static_cast<bool>(::std::forward<T>(of) op ::std::forward<U>(other)))) {
    return chained_comparisons<U>{ ::std::forward<U>(other), value && static_cast<bool>(::std::forward<T>(of) op ::std::forward<U>(other)) };
    }

    template<class U>
    constexpr
    chained_comparisons<U> operator op (const chained_comparisons<U>& other) const
    noexcept(noexcept(static_cast<bool>(::std::forward<T>(of) op ::std::forward<U>(other.of)))) {
    return chained_comparisons<U>{ other.of, value && other.value && static_cast<bool>(::std::forward<T>(of) op ::std::forward<U>(other.of)) };
    }

    DEFINE_ALL_CHAINED_COMPARISON_OPERATORS

    #undef DEFINE_CHAINED_COMPARISON_OPERATOR

    // Convert to bool implicitly
    constexpr operator bool() const noexcept { return value; }
    constexpr bool operator!() const noexcept { return !value; }
    };

    // Define functions to be able to have the chain_comparison<T> on the right side as well
    #define DEFINE_CHAINED_COMPARISON_OPERATOR(op) template<class T, class U>
    constexpr
    typename ::std::enable_if<!detail::is_chained_comparison<U>::value, chained_comparisons<T>>::type
    operator op (U&& other, const chained_comparisons<T>& self)
    noexcept(noexcept(static_cast<bool>(::std::forward<U>(other) op ::std::forward<T>(self.of)))) {
    return chained_comparisons<T>{ ::std::forward<T>(self.of), self.value && static_cast<bool>(::std::forward<U>(other) op ::std::forward<T>(self.of)) };
    }

    DEFINE_ALL_CHAINED_COMPARISON_OPERATORS

    #undef DEFINE_CHAINED_COMPARISON_OPERATOR
    #undef DEFINE_ALL_CHAINED_COMPARISON_OPERATORS

    // c is a shorthand helper to begin chained comparisons.
    // c >> X <= Y <= Z, c / X <= Y <= Z, or c(X) <= Y <= Z.
    static const detail::chained_comparisons_helper c;

    }


    (test.cpp)



    #include "./chained_comparisons.h"

    #include <iostream>
    #include <ios>
    #include <cstddef>

    int main() {
    using ::chained_comparisons::c;

    ::std::boolalpha(::std::cout);

    // Disable warning produced by X<=Y<=Z
    #pragma GCC diagnostic push
    #pragma GCC diagnostic ignored "-Wparentheses"
    // false (((-3 <= -1) < 0) -> ((true) < 0) -> (1 < 0) -> false)
    ::std::cout << "-3 <= -1 < 0: " << (-3 <= -1 < 0) << 'n';

    // Both true
    ::std::cout << "c(-3) <= -1 < 0: " << (c(-3) <= -1 < 0) << 'n';
    ::std::cout << "c >> -3 <= -1 < 0: " << (c >> -3 <= -1 < 0) << 'n';
    #pragma GCC diagnostic pop
    }


    I've tried to have perfect forwarding through all the functions (c -> chained_comparison -> operator op), so this could theoretically support a non-const comparison method without making copies (Though this breaks if you don't expect the comparison to be convertible to a bool, which is understandable).



    There are two issues I have right now.



    First is that I use a lot of macros. But this prevents duplicating code 6 times for all the operators, so I find this understandable. Is there a better way to define the similar functions?



    The second issue is that I don't think this is easy to read. I can read it now that I've just written it, but I don't think I'd be able to read it again after some time. Is this because I'm writing something very wierd / uncommon, or am I making a stylistic mistake?



    Also, I don't know if this is very practical. I think c >> X <= Y <= Z is clunkier to write than X <= Y && Y <= Z (And more people would know what the second is saying). It compiles to the same thing in the end, which seems to suggest that I forwarded properly.










    share|improve this question

























      0












      0








      0







      In many languages, X <= Y <= Z is equivalent to X <= Y && Y <= Z. This is not so in C++, and g++ produces this warning if we do try to write that:



      comparisons like ‘X<=Y<=Z’ do not have their mathematical meaning


      So I tried to impement that in C++ (C++11):



      (chained_comparisons.h)





      #include <utility>
      #include <type_traits>


      namespace chained_comparisons {
      template<class T>
      class chained_comparisons;

      namespace detail {
      template<class T>
      struct is_chained_comparison_helper : ::std::false_type::type {};

      template<class T>
      struct is_chained_comparison_helper<chained_comparisons<T>> : ::std::true_type::type {};

      template<class T>
      struct is_chained_comparison : is_chained_comparison_helper<typename ::std::remove_cv<typename ::std::remove_reference<T>::type>::type>::type {};

      struct chained_comparisons_helper {
      template<class T>
      constexpr chained_comparisons<T> operator()(T&& of) const noexcept {
      return chained_comparisons<T>{ ::std::forward<T>(of) };
      }

      // Alternative to c(...) is c >> ..., as >> has higher precedence
      // than comparison operators, and nothing has to go to the right of the first value.
      // And it looks like the rhs is being "imbued" with the ability to chain comparison.
      template<class T>
      constexpr chained_comparisons<T> operator>>(T&& of) const noexcept {
      return chained_comparisons<T>{ ::std::forward<T>(of) };
      }

      // Provided to silence compilers that warn about precedence in "A >> B < C".
      // Use `A * B < C` instead.
      template<class T>
      constexpr chained_comparisons<T> operator/(T&& of) const noexcept {
      return chained_comparisons<T>{ ::std::forward<T>(of) };
      }
      };
      }

      // This class holds a reference and whether the comparisons chained so far have
      // succeeded. The only way for a comparison with this class to succeed is if
      // all previous comparisons have succeeded and comparison with the reference succeeds.
      template<class T>
      class chained_comparisons {
      public:
      T&& of;
      bool value = true;
      explicit constexpr chained_comparisons(T&& of_, bool value_ = true) noexcept : of(::std::forward<T>(of_)), value(value_) {};

      // Helper macro that expands DEFINE_CHAINED_COMPARISON_OPERATOR for all comparison operators
      #define DEFINE_ALL_CHAINED_COMPARISON_OPERATORS
      DEFINE_CHAINED_COMPARISON_OPERATOR(==)
      DEFINE_CHAINED_COMPARISON_OPERATOR(!=)
      DEFINE_CHAINED_COMPARISON_OPERATOR(>)
      DEFINE_CHAINED_COMPARISON_OPERATOR(<)
      DEFINE_CHAINED_COMPARISON_OPERATOR(>=)
      DEFINE_CHAINED_COMPARISON_OPERATOR(<=)

      // Define member functions to chain comparisons (1) generally and (2) with other chained_comparison<U>
      #define DEFINE_CHAINED_COMPARISON_OPERATOR(op)
      template<class U>
      constexpr
      chained_comparisons<U> operator op (U&& other) const
      noexcept(noexcept(static_cast<bool>(::std::forward<T>(of) op ::std::forward<U>(other)))) {
      return chained_comparisons<U>{ ::std::forward<U>(other), value && static_cast<bool>(::std::forward<T>(of) op ::std::forward<U>(other)) };
      }

      template<class U>
      constexpr
      chained_comparisons<U> operator op (const chained_comparisons<U>& other) const
      noexcept(noexcept(static_cast<bool>(::std::forward<T>(of) op ::std::forward<U>(other.of)))) {
      return chained_comparisons<U>{ other.of, value && other.value && static_cast<bool>(::std::forward<T>(of) op ::std::forward<U>(other.of)) };
      }

      DEFINE_ALL_CHAINED_COMPARISON_OPERATORS

      #undef DEFINE_CHAINED_COMPARISON_OPERATOR

      // Convert to bool implicitly
      constexpr operator bool() const noexcept { return value; }
      constexpr bool operator!() const noexcept { return !value; }
      };

      // Define functions to be able to have the chain_comparison<T> on the right side as well
      #define DEFINE_CHAINED_COMPARISON_OPERATOR(op) template<class T, class U>
      constexpr
      typename ::std::enable_if<!detail::is_chained_comparison<U>::value, chained_comparisons<T>>::type
      operator op (U&& other, const chained_comparisons<T>& self)
      noexcept(noexcept(static_cast<bool>(::std::forward<U>(other) op ::std::forward<T>(self.of)))) {
      return chained_comparisons<T>{ ::std::forward<T>(self.of), self.value && static_cast<bool>(::std::forward<U>(other) op ::std::forward<T>(self.of)) };
      }

      DEFINE_ALL_CHAINED_COMPARISON_OPERATORS

      #undef DEFINE_CHAINED_COMPARISON_OPERATOR
      #undef DEFINE_ALL_CHAINED_COMPARISON_OPERATORS

      // c is a shorthand helper to begin chained comparisons.
      // c >> X <= Y <= Z, c / X <= Y <= Z, or c(X) <= Y <= Z.
      static const detail::chained_comparisons_helper c;

      }


      (test.cpp)



      #include "./chained_comparisons.h"

      #include <iostream>
      #include <ios>
      #include <cstddef>

      int main() {
      using ::chained_comparisons::c;

      ::std::boolalpha(::std::cout);

      // Disable warning produced by X<=Y<=Z
      #pragma GCC diagnostic push
      #pragma GCC diagnostic ignored "-Wparentheses"
      // false (((-3 <= -1) < 0) -> ((true) < 0) -> (1 < 0) -> false)
      ::std::cout << "-3 <= -1 < 0: " << (-3 <= -1 < 0) << 'n';

      // Both true
      ::std::cout << "c(-3) <= -1 < 0: " << (c(-3) <= -1 < 0) << 'n';
      ::std::cout << "c >> -3 <= -1 < 0: " << (c >> -3 <= -1 < 0) << 'n';
      #pragma GCC diagnostic pop
      }


      I've tried to have perfect forwarding through all the functions (c -> chained_comparison -> operator op), so this could theoretically support a non-const comparison method without making copies (Though this breaks if you don't expect the comparison to be convertible to a bool, which is understandable).



      There are two issues I have right now.



      First is that I use a lot of macros. But this prevents duplicating code 6 times for all the operators, so I find this understandable. Is there a better way to define the similar functions?



      The second issue is that I don't think this is easy to read. I can read it now that I've just written it, but I don't think I'd be able to read it again after some time. Is this because I'm writing something very wierd / uncommon, or am I making a stylistic mistake?



      Also, I don't know if this is very practical. I think c >> X <= Y <= Z is clunkier to write than X <= Y && Y <= Z (And more people would know what the second is saying). It compiles to the same thing in the end, which seems to suggest that I forwarded properly.










      share|improve this question













      In many languages, X <= Y <= Z is equivalent to X <= Y && Y <= Z. This is not so in C++, and g++ produces this warning if we do try to write that:



      comparisons like ‘X<=Y<=Z’ do not have their mathematical meaning


      So I tried to impement that in C++ (C++11):



      (chained_comparisons.h)





      #include <utility>
      #include <type_traits>


      namespace chained_comparisons {
      template<class T>
      class chained_comparisons;

      namespace detail {
      template<class T>
      struct is_chained_comparison_helper : ::std::false_type::type {};

      template<class T>
      struct is_chained_comparison_helper<chained_comparisons<T>> : ::std::true_type::type {};

      template<class T>
      struct is_chained_comparison : is_chained_comparison_helper<typename ::std::remove_cv<typename ::std::remove_reference<T>::type>::type>::type {};

      struct chained_comparisons_helper {
      template<class T>
      constexpr chained_comparisons<T> operator()(T&& of) const noexcept {
      return chained_comparisons<T>{ ::std::forward<T>(of) };
      }

      // Alternative to c(...) is c >> ..., as >> has higher precedence
      // than comparison operators, and nothing has to go to the right of the first value.
      // And it looks like the rhs is being "imbued" with the ability to chain comparison.
      template<class T>
      constexpr chained_comparisons<T> operator>>(T&& of) const noexcept {
      return chained_comparisons<T>{ ::std::forward<T>(of) };
      }

      // Provided to silence compilers that warn about precedence in "A >> B < C".
      // Use `A * B < C` instead.
      template<class T>
      constexpr chained_comparisons<T> operator/(T&& of) const noexcept {
      return chained_comparisons<T>{ ::std::forward<T>(of) };
      }
      };
      }

      // This class holds a reference and whether the comparisons chained so far have
      // succeeded. The only way for a comparison with this class to succeed is if
      // all previous comparisons have succeeded and comparison with the reference succeeds.
      template<class T>
      class chained_comparisons {
      public:
      T&& of;
      bool value = true;
      explicit constexpr chained_comparisons(T&& of_, bool value_ = true) noexcept : of(::std::forward<T>(of_)), value(value_) {};

      // Helper macro that expands DEFINE_CHAINED_COMPARISON_OPERATOR for all comparison operators
      #define DEFINE_ALL_CHAINED_COMPARISON_OPERATORS
      DEFINE_CHAINED_COMPARISON_OPERATOR(==)
      DEFINE_CHAINED_COMPARISON_OPERATOR(!=)
      DEFINE_CHAINED_COMPARISON_OPERATOR(>)
      DEFINE_CHAINED_COMPARISON_OPERATOR(<)
      DEFINE_CHAINED_COMPARISON_OPERATOR(>=)
      DEFINE_CHAINED_COMPARISON_OPERATOR(<=)

      // Define member functions to chain comparisons (1) generally and (2) with other chained_comparison<U>
      #define DEFINE_CHAINED_COMPARISON_OPERATOR(op)
      template<class U>
      constexpr
      chained_comparisons<U> operator op (U&& other) const
      noexcept(noexcept(static_cast<bool>(::std::forward<T>(of) op ::std::forward<U>(other)))) {
      return chained_comparisons<U>{ ::std::forward<U>(other), value && static_cast<bool>(::std::forward<T>(of) op ::std::forward<U>(other)) };
      }

      template<class U>
      constexpr
      chained_comparisons<U> operator op (const chained_comparisons<U>& other) const
      noexcept(noexcept(static_cast<bool>(::std::forward<T>(of) op ::std::forward<U>(other.of)))) {
      return chained_comparisons<U>{ other.of, value && other.value && static_cast<bool>(::std::forward<T>(of) op ::std::forward<U>(other.of)) };
      }

      DEFINE_ALL_CHAINED_COMPARISON_OPERATORS

      #undef DEFINE_CHAINED_COMPARISON_OPERATOR

      // Convert to bool implicitly
      constexpr operator bool() const noexcept { return value; }
      constexpr bool operator!() const noexcept { return !value; }
      };

      // Define functions to be able to have the chain_comparison<T> on the right side as well
      #define DEFINE_CHAINED_COMPARISON_OPERATOR(op) template<class T, class U>
      constexpr
      typename ::std::enable_if<!detail::is_chained_comparison<U>::value, chained_comparisons<T>>::type
      operator op (U&& other, const chained_comparisons<T>& self)
      noexcept(noexcept(static_cast<bool>(::std::forward<U>(other) op ::std::forward<T>(self.of)))) {
      return chained_comparisons<T>{ ::std::forward<T>(self.of), self.value && static_cast<bool>(::std::forward<U>(other) op ::std::forward<T>(self.of)) };
      }

      DEFINE_ALL_CHAINED_COMPARISON_OPERATORS

      #undef DEFINE_CHAINED_COMPARISON_OPERATOR
      #undef DEFINE_ALL_CHAINED_COMPARISON_OPERATORS

      // c is a shorthand helper to begin chained comparisons.
      // c >> X <= Y <= Z, c / X <= Y <= Z, or c(X) <= Y <= Z.
      static const detail::chained_comparisons_helper c;

      }


      (test.cpp)



      #include "./chained_comparisons.h"

      #include <iostream>
      #include <ios>
      #include <cstddef>

      int main() {
      using ::chained_comparisons::c;

      ::std::boolalpha(::std::cout);

      // Disable warning produced by X<=Y<=Z
      #pragma GCC diagnostic push
      #pragma GCC diagnostic ignored "-Wparentheses"
      // false (((-3 <= -1) < 0) -> ((true) < 0) -> (1 < 0) -> false)
      ::std::cout << "-3 <= -1 < 0: " << (-3 <= -1 < 0) << 'n';

      // Both true
      ::std::cout << "c(-3) <= -1 < 0: " << (c(-3) <= -1 < 0) << 'n';
      ::std::cout << "c >> -3 <= -1 < 0: " << (c >> -3 <= -1 < 0) << 'n';
      #pragma GCC diagnostic pop
      }


      I've tried to have perfect forwarding through all the functions (c -> chained_comparison -> operator op), so this could theoretically support a non-const comparison method without making copies (Though this breaks if you don't expect the comparison to be convertible to a bool, which is understandable).



      There are two issues I have right now.



      First is that I use a lot of macros. But this prevents duplicating code 6 times for all the operators, so I find this understandable. Is there a better way to define the similar functions?



      The second issue is that I don't think this is easy to read. I can read it now that I've just written it, but I don't think I'd be able to read it again after some time. Is this because I'm writing something very wierd / uncommon, or am I making a stylistic mistake?



      Also, I don't know if this is very practical. I think c >> X <= Y <= Z is clunkier to write than X <= Y && Y <= Z (And more people would know what the second is saying). It compiles to the same thing in the end, which seems to suggest that I forwarded properly.







      c++ c++11 overloading






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked 14 mins ago









      Artyer

      1416




      1416



























          active

          oldest

          votes











          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f210146%2fimplementing-chained-comparisons-by-overloading-operators%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown






























          active

          oldest

          votes













          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes
















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Code Review Stack Exchange!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          Use MathJax to format equations. MathJax reference.


          To learn more, see our tips on writing great answers.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f210146%2fimplementing-chained-comparisons-by-overloading-operators%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Feedback on college project

          Futebolista

          Albești (Vaslui)