TartanLlama / optional

C++11/14/17 std::optional with functional-style extensions and reference support
https://tl.tartanllama.xyz
Creative Commons Zero v1.0 Universal
858 stars 67 forks source link

`tl::optional` comparison operators do not work with template checks #58

Open SeverinTobler opened 1 year ago

SeverinTobler commented 1 year ago

Checking with templates whether tl::optional<T> is comparable returns the wrong result, if T is not comparable (check works with std::optional). For example:

#include <experimental/type_traits>

template <typename T, typename U>
using equality_comparison = decltype(std::declval<T const&>() == std::declval<U const&>());

struct NoCompare {}; // lacks comparison operators

// this assert fails, but equal comparison with tl::optional<NoCompare> doesn't compile
static_assert(!std::experimental::is_detected<equality_comparison, tl::optional<NoCompare>, NoCompare>::value,
              "'tl::optional<NoCompare> == NoCompare' should not compile");

Note: I ran into this issue using tl::optional with Trompeloil (https://github.com/rollbear/trompeloeil), as Trompeloil checks this way whether function parameters are comparable to nullptr.

SeverinTobler commented 1 year ago

I suggest to solve this issue by adding enable_if to the comparison operators, to propagate the comparison trait of T and U to the tl::optional comparison operators.

Audiodroid commented 1 year ago

I seem to have the same or a similar issue. Is there a workaround for this as long as this has not been addressed?

class SomeMock {
    MAKE_MOCK0 (someFunctionReturnTlOptional, tl::optional<std::string>());
};

TEST_CASE("my test") {
    tl::optional<std::string> myTlOptional = "some string";

    SomeMock someMock;
    ALLOW_CALL(someMock, someFunctionReturningTlOptional()).RETURN(myTlOptional);
}

Then compiler says:

optional/include/tl/optional.hpp:1425:33: error: invalid operands to binary expression ('const std::string' and 'const std::nullptr_t')
  return lhs.has_value() ? *lhs == rhs : false;

The referenced code @ optional.hpp:1425 is:

template <class T, class U>
inline constexpr bool operator==(const optional<T> &lhs, const U &rhs) {
  return lhs.has_value() ? *lhs == rhs : false;
}