Software! Math! Data! The blog of R. Sean Bowman
The blog of R. Sean Bowman
November 22 2016

Recently I needed a way to check whether a callable C++ thing (like a lambda) could be applied to a given list of potential arguments. More precisely, I wanted to know, given a lambda f and list of arguments a1, a2, ..., an, whether the expression f(a1, a2, ..., an) would compile. I came up with a way to do it that I’m pleased with. Here’s an example of the interface:

auto f = [](int x) { return x + 1; };

can_apply(f, 3); // returns true, f(3) makes sense
can_apply(f, "hey"); // returns false
can_apply(f, 4, 5); // returns false

I’m posting the code below, but the latest version of the code together with explanation is on github. Please check there if you’re interested.

Note: The C++ standard specifies exactly what it means by “callable” (see std::is_callable in C++17), and that’s not what I’m doing here. In particular, this doesn’t work too well with member functions. It could very well be wrong in a bunch of other ways. C++ is complicated. Don’t use this in your pacemaker software.

#include <iostream>
#include <cassert>

template <typename F, typename... Args>
class CanApply {
protected:
    template <typename F2, typename... Args2>
    struct Fargs {};

    template <typename Fgs, typename = void>
    struct CanApplyHelper {
        static constexpr bool value = false;
    };

    template <typename F2, typename... Args2>
    struct CanApplyHelper<
        Fargs<F2, Args2...>,
        decltype(std::declval<F2>().operator()(std::declval<Args2>()...), void())
    > {
        static constexpr bool value = true;
    };

public:
    static constexpr bool value = CanApplyHelper<Fargs<F, Args...>>::value;
};

template <typename F, typename... Args>
constexpr bool can_apply(F&& f, Args&&... args) {
    return CanApply<decltype(f), decltype(args)...>::value;
}

Approx. 261 words, plus code