Vittorio Romeo Vittorio Romeo - 11 months ago 92
C++ Question

Getting SFINAE to work with `is_callable` on an overloaded function object

Consider the following function object


auto l = [](auto x){; };

I can successfully
that it is callable with a type that has a
member function:

struct Foo { void foo(); };

I would now like
to evaluate to
if I use a type that does not have a
member function:


Unfortunately, the above
results in a compilation error: In instantiation of '<lambda(auto:1)> [with auto:1 = int]': required by substitution of 'template<class TF, class ... Ts>
struct is_callable<TF(Ts ...),
std::void_t<decltype (declval<TF>()((declval<Ts>)()...))>
> [with TF = <lambda(auto:1)>; Ts = {int}]' required from here error: request for member 'foo' in 'x', which is of non-class type 'int'
auto l = [](auto x){; };

I also tried implementing my own
by using
as follows, getting the same compilation error:

template <typename, typename = void>
struct is_callable : std::false_type { };

template <typename TF, class... Ts>
struct is_callable<TF(Ts...),
: std::true_type { };

I was under the impression that the
fallback would be chosen if the expression inside
std::void_t<decltype(/* ... */)>
was not valid due to SFINAE.

  • Why is this SFINAE not taking place here, resulting in a compilation error?

  • How can I achieve my desired behavior? (i.e. evaluate to
    if calling the overloaded function object is ill-formed)

live example on wandbox (C++14 compliant)

Answer Source

Your lambda does not constrain it's​ arguments with sfinae. Your lambda is callable with anything, but triggers hard compilation errors when instantiated with these arguments.

To get the desired effect, put constraints on the return type:

auto l = [](auto x) -> void_t<decltype(> {; };

That way, the is_callable trait will yield the correct result.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download