1
votes

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:

1
Can you provide a minimal reproducible example? Like the second alreadyValue overload should be a template presumably, etc.Barry
I would recommend using if constexpr for these kind of cases. Much easier to read. See stackoverflow.com/a/51659883/2466431JVApen
@JVApen, thanks, I never knew that I could inline an constexpr like that.Rhaokiel
For SFINAE you need an unevaluated context and dependent types. You seem to have neither. What is it that you're trying to accomplish? As to why MSVC accepts this. Well, it's just not a very good C++ compiler. Especially if you go for these kinds of things.rubenvb
As it is currently presented, T is template param of the class and not the method (obviously). This could be related to the following question.Mike Spencer

1 Answers

1
votes

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);
}