Is there a way to detect at compile time, is it possible to successfully use a common lambda with a given set of parameter types?

I would like to be able to determine at compile time, taking into account the general type of lambda, whether it can be called with a given set of parameter types. I have the following C ++ 14 implementation example:

#include <iostream>

// helper function; this overload handles the case that the call is possible
// use SFINAE with the extra template parameter to remove this from consideration when the
// call is ill-formed
template <typename Func, typename... Args, typename = decltype(std::declval<Func>()(std::declval<Args>()...))>
auto eval(Func f, Args &&... args) { return f(args...); }

// special type returned from `eval()` when the call can't be done
struct invalid_call { };

// helper function; this overload handles the case that the call is not possible
template <typename Func>
invalid_call eval(Func f, ...) { return invalid_call{}; };

// bring in std::negation from C++17 to help create the below trait
template<class B>
struct negation : std::integral_constant<bool, !bool(B::value)> { };

// trait that determines whether `Func` can be invoked with an argument list of types `Args...`
template <typename Func, typename... Args>
using can_call = negation<std::is_same<decltype(eval(std::declval<Func>(), std::declval<Args>()...)), invalid_call>>;

// arbitary type that has no `operator+`
struct foo {};

int main()
{
    auto func = [](auto a1, auto a2) -> decltype(a1 + a2) { return a1 + a2; };
    using FuncType = decltype(func);

    std::cout << "can call with (int, int): " << can_call<FuncType, int, int>::value << std::endl;
    std::cout << "can call with (foo, foo): " << can_call<FuncType, foo, foo>::value << std::endl;
}

This example works great as it is. What I am not is a cumbersome way to declare a lambda:

auto func = [](auto a1, auto a2) -> decltype(a1 + a2) { return a1 + a2; };

That is, the return type of the return must be specified, because C ++ 14 return types do not work with SFINAE . Returning the output type requires substituting the types of the argument list into the calling template call operator, and the program is poorly formed if an error occurs there.

Ideally, I could do the following:

auto func = [](auto a1, auto a2) { return a1 + a2; };

; . , decltype() , , . :

++ ( ++ 14, ), , ?

+4
1

,

++ 98
#define RETURNS(...) noexcept(noexcept(__VA_ARGS__))->decltype(__VA_ARGS__) { return __VA_ARGS__; }

auto func = [](auto a1, auto a2) RETURNS(a1+a2);

.

@Barry ++ 20,

auto func = [](auto a1, auto a2) => a1+a2;

.

, , , SFINAE . , ++; , , , .

return , return, . decltype. , .

+3

Source: https://habr.com/ru/post/1676774/


All Articles