Rhaokiel
Rhaokiel

Reputation: 843

What's wrong with my SFINAE?: Testing Supported Operators

This is the code that has the problem:

template <typename=std::enable_if_t<supports_v<std::equal_to<>, T>> >
bool alreadyValue(const T &value) { return this->value == value; }
// alternate case if T does not support equals operator
bool alreadyValue(const T &value) { return false; }

Here's my support definitions:

template<typename F, typename... T, typename = decltype(std::declval<F>()(std::declval<T>()...))>
std::true_type  supports_test(const F&, const T&...);
std::false_type supports_test(...);

template<typename> struct supports;
template<typename F, typename... T> struct supports<F(T...)>
    : decltype(supports_test(std::declval<F>(), std::declval<T>()...)){};

template<typename F, typename T>
constexpr bool supports_v = supports<F(T, T)>::value;

template<typename F, typename... T>
constexpr bool all_supports_v = (supports<F(T, T)>::value && ...);

Now, MSVC 19.20 has no problem with this code.

But GCC 9.1 complains that:

In substitution of 'template<bool _Cond, class _Tp> using enable_if_t = typename std::enable_if::type [with bool _Cond = supports_v<std::equal_to<void>, A>; _Tp = void]':

error: no type named 'type' in 'struct std::enable_if<false, void>'

Since SFINAE knows that "no type in struct" should fail silently as its not an error, my question is did I do something wrong?

Here's an example of what I'm working with:

Upvotes: 1

Views: 336

Answers (1)

Rhaokiel
Rhaokiel

Reputation: 843

As @rubenvb stated and @Mike Spencer alluded to, the enable_if is not in an unevaluated context because there is no generic type dependent on the function. So no SFINAE.

As a solution, I instead built the function as a generic support function:

template<typename T, bool=supports_v<std::equal_to<>, T>>
struct is_equal_t;
template<typename T>
struct is_equal_t<T, true> {
    bool operator() (const T& x, const T& y) const { return x==y; }
};
template<typename T>
struct is_equal_t<T, false> {
    bool operator() (const T& x, const T& y) const { return false; }
};

template<typename T>
bool is_equal(const T& x, const T& y) {
    static is_equal_t<T> cmp;
    return cmp(x, y);
}

Upvotes: 1

Related Questions