zrb
zrb

Reputation: 891

Generic lambda functions with template parameters

 #include <utility>
 #include <tuple>

 template < typename T, typename U >
 void h(T, U)
 {
 }

 template < typename... T, typename... U >
 void f(std::tuple < T... >  t, std::tuple < U... >  u)
 {
     auto g = [&] < std::size_t... I > (std::index_sequence < I... >)
              {
                  bool const r[]{((void)h(std::get < I >(t), std::get < I >(u)), false)...};
                  (void)r;
             };
     g(std::index_sequence_for < T... >());
 }

 int main()
 {
     f(std::make_tuple(0L, 0LL), std::make_tuple(0UL, 0ULL));
 }

The above compiles with g++ test_templated_lambda.cpp -o test_templated_lambda -std=c++14, but doesn't compile with clang++ test_templated_lambda.cpp -o test_templated_lambda -std=c++14

I know it is a GCC extension (Using template parameter in a generic lambda), but is there some way to do this without writing out g as a free function

Upvotes: 4

Views: 935

Answers (1)

ecatmur
ecatmur

Reputation: 157324

This is not possible without some external help; generic lambdas are the only form of template permitted within a function scope, and they cannot be specialized or overloaded (without some external helper, such as P0051R1 overload).

It is possible to write a compile-time loop by embedding a recursive generic lambda in your function, but (a) you'll have to convert it to fix-point combinator form, and (b) terminating it is seriously ugly:

[&](auto&& g) {
  g(g, std::integral_constant<std::size_t, 0u>{});
}([&](auto&& g, auto I) {
  h(std::get<I>(t), std::get<I>(u));
  std::get<I + 1 == sizeof...(T)>(std::make_pair(
    [&](auto&& g) { g(g, std::integral_constant<std::size_t, I + 1>{}); },
    [](auto&&){}))(g);
});

Example.

You're already using an external helper facility (std::index_sequence_for), so why not write another? For example:

template<class F, std::size_t... I> auto apply_indexes(F&& f, std::index_sequence<I...>) {
  return std::forward<F>(f)(std::integral_constant<std::size_t, I>{}...);
}

Usage:

auto g = [&](auto... I)
{
  bool const r[]{((void)h(std::get<I>(t), std::get<I>(u)), false)...};
  (void)r;
};
apply_indexes(g, std::index_sequence_for<T...>());

Upvotes: 3

Related Questions