I'd like to pass templated functions around as if they were generic lambdas, however this does not work.
#include <iostream>
#include <vector>
#include <tuple>
#include <string>
#include <utility>
// for_each with std::tuple
// (from https://stackoverflow.com/a/6894436/1583122)
template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
for_each(std::tuple<Tp...> &, FuncT)
{}
template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
for_each(std::tuple<Tp...>& t, FuncT f) {
f(std::get<I>(t));
for_each<I + 1, FuncT, Tp...>(t, f);
}
// my code
template<class T> auto
print(const std::vector<T>& v) -> void {
for (const auto& e : v) {
std::cout << e << "\t";
}
}
struct print_wrapper {
template<class T>
auto operator()(const std::vector<T>& v) {
print(v);
}
};
auto print_gen_lambda = [](const auto& v){ print(v); };
auto print_gen_lambda_2 = []<class T>(const std::vector<T>& v){ print(v); }; // proposal P0428R1, gcc extension in c++14/c++17
int main() {
std::tuple<std::vector<int>,std::vector<double>,std::vector<std::string>> t = { {42,43},{3.14,2.7},{"Hello","World"}};
for_each(t, print); // case 1: error: template argument deduction/substitution failed: couldn't deduce template parameter 'FuncT'
for_each(t, print_wrapper()); // case 2: ok
for_each(t, print_gen_lambda); // case 3: ok
for_each(t, print_gen_lambda_2); // case 4: ok
}
Note that case 2 and 4 are strictly equivalent. Case 3 is more general but unconstrained (this is a problem for me). I think that case 1 should be treated equivalently to cases 2 and 4 by the language, however this is not the case.
Is there, in C++14/17/20, a very terse manner to enable the conversion from case 1 to case 2? I am even open to macro hacks.
Lambda-expressions are not allowed in unevaluated expressions, template arguments, alias declarations, typedef declarations, and anywhere in a function (or function template) declaration except the function body and the function's default arguments.
Generic lambdasLambda function parameters can now be auto to let the compiler deduce the type. This generates a lambda type with a templated operator() so that the same lambda object can be invoked with any suitable type and a type-safe function with the right parameter type will be automatically generated.
Generic lambdas were introduced in C++14 . Simply, the closure type defined by the lambda expression will have a templated call operator rather than the regular, non-template call operator of C++11 's lambdas (of course, when auto appears at least once in the parameter list).
C++ Generic lambdas. Example. c++14. Lambda functions can take arguments of arbitrary types. This allows a lambda to be more generic: auto twice = [](auto x){ return x+x; }; int i = twice(2); // i == 4 std::string s = twice("hello"); // s == "hellohello".
The functional interface can be generic (template). In this case, the target type of the lambda expression is determined based on the type specified in the reference to that functional interface. For example. Let the generalized functional interface IValue be given
You can do this by wrapping the function argument in an identity type so that it doesn't fail on trying to match the lambda to std::function (because dependent types are just ignored by type deduction) and giving some other arguments. template <typename T> struct identity { typedef T type; }; template <typename...
It is possible to get the needed std::function type for lambda using derivation, decltype, variadic templates and a few type traits: namespace ambient { template <typename Function> struct function_traits : public function_traits<decltype (&Function::operator ())> {}; template <typename ClassType, typename ReturnType, typename...
Is there, in C++14/17/20, a very terse manner to enable the conversion from case 1 to case 2? I am even open to macro hacks.
Yes.
// C++ requires you to type out the same function body three times to obtain
// SFINAE-friendliness and noexcept-correctness. That's unacceptable.
#define RETURNS(...) noexcept(noexcept(__VA_ARGS__)) \
-> decltype(__VA_ARGS__){ return __VA_ARGS__; }
// The name of overload sets can be legally used as part of a function call -
// we can use a macro to create a lambda for us that "lifts" the overload set
// into a function object.
#define LIFT(f) [](auto&&... xs) RETURNS(f(::std::forward<decltype(xs)>(xs)...))
You can then say:
for_each(t, LIFT(print));
Is there a proposal to implicitly convert a template function to a generic constrained lambda?
Yes, look at P0119 or N3617. Not sure about their status.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With