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 << "";
}
}
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 a proposal to implicitly convert a template function to a generic constrained lambda (case 2/4)? If no, is there a fundamental language reason that prevents from doing so?
- As of now, I have to use case 2, which is quite cumbersome.
- case 4: not c++14-compliant, even if should be standard in c++20, and still not perfect (verbose since you create a lambda that fundamentally does not add any information).
- case 3: is unconstrained, but I rely (not shown here) on substitution failure for calls to "print" with non-"vector" arguments (P0428R1 mentions this problem). So I guess the subsidiary question is "Can I constrain a generic lambda with some enable_if tricks?"
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.
See Question&Answers more detail:os