Can Lambda Functions Be Templated

Can lambda functions be templated?

UPDATE 2018: C++20 will come with templated and conceptualized lambdas. The feature has already been integrated into the standard draft.


UPDATE 2014: C++14 has been released this year and now provides Polymorphic lambdas with the same syntax as in this example. Some major compilers already implement it.


At it stands (in C++11), sadly no. Polymorphic lambdas would be excellent in terms of flexibility and power.

The original reason they ended up being monomorphic was because of concepts. Concepts made this code situation difficult:

template <Constraint T>
void foo(T x)
{
auto bar = [](auto x){}; // imaginary syntax
}

In a constrained template you can only call other constrained templates. (Otherwise the constraints couldn't be checked.) Can foo invoke bar(x)? What constraints does the lambda have (the parameter for it is just a template, after all)?

Concepts weren't ready to tackle this sort of thing; it'd require more stuff like late_check (where the concept wasn't checked until invoked) and stuff. Simpler was just to drop it all and stick to monomorphic lambdas.

However, with the removal of concepts from C++0x, polymorphic lambdas become a simple proposition again. However, I can't find any proposals for it. :(

Can a lambda instantiate a template function?

The answer to your question is technically yes, lambda bodies can instantiate template functions. The actual example doesn't work, because int n as a parameter can't be used that way.

There is an easy workaround

template<auto x>
using constant_t = std::integral_constant< std::decay_t<decltype(x)>, x >;
template<auto x>
constexpr constant_t<x> constant = {};

template <int n> int fn () { int arr[n] = {0}; return sizeof(arr); }
auto fx = [] (auto n) { return fn<n>(); };
std::cout << fx( constant<3> );

Live example.

Here I made the constant<x> variable template that creates an instance of std::integral_constant<X, x>. This is a stateless (but not valueless!) type that has a constexpr conversion to its value.

We can pass that to a lambda, and so long as the lambda takes it by value we can then convert it to a constexpr value within the lambda, including passing it as a template non-type parameter, instantiating a template function specialization as you are asking for.

The can be done without the constant variable template, ie if you don't have auto parameter support:

template<std::size_t N>
using index_t = std::integral_constant<std::size_t, N>;
template<std::size_t N>
constexpr index_t<N> index = {};

we can use a type-specific version of it, and just pass that, and it works the same way.


Aside, constant<?> is fun. For example:

using upFILE=std::unique_ptr<
std::FILE,
constant_t<std::fclose>
>;

upFILE file( fopen("hello.txt", "r") );

does the right thingtm.

Templated lambdas in C++17 without an auto argument

Template parameter lists in lambda expressions is a C++20 feature.

(In fact, my GCC says that in the diagnostic: error: lambda templates are only available with -std=c++2a or -std=gnu++2a [-Wpedantic])

But you don't have to wait for C++20, it's already supported by GCC 8 with -std=c++2a flag.

And you'll have to change the call syntax: Instead of derived_factory<int>(), you need derived_factory.operator()<int>().


As an alternative (if you don't want a free function), I suggest using a variation of tag dispatch:

auto derived_factory = [](auto tag) {
return new Derived<typename tag::type>();
};

template <typename T> struct tag_type {using type = T;};

// Usage:
derived_factory(tag_type<int>{})

Also, even if you make it compile somehow, this line:

auto derived = *(derived_factory<int>());

will cause a memory leak no matter what. To avoid that, you should store the result as a pointer or a reference. Or even better, use a smart pointer.

Pass C++20 Templated Lambda to Function Then Call it

The issue is that lambdas are not class templates, they're just regular classes where the member call operator, i.e. operator() is templated.

When the template parameters are deduced for a generic lambda, this distinction is not noticeable (which is a very good thing).

So in your example, lambda is not a class template, but you are using syntax that would be used for a class, not a member function.

If you want to specify the template parameters for a lambda explicitly, you'll need to say that you're calling the member operator() of lambda, and you'll need to say that it's a template to disambiguate.

lambda.template operator()<Alignment::eight>(t.data(), t.size());

Here's the version of your code that compiles.

What is the need of template lambda introduced in C++20 when C++14 already has generic lambda?

C++14 generic lambdas are a very cool way to generate a functor with an operator () that looks like this:

template <class T, class U>
auto operator()(T t, U u) const;

But not like this:

template <class T>
auto operator()(T t1, T t2) const; // Same type please

Nor like this:

template <class T, std::size_t N>
auto operator()(std::array<T, N> const &) const; // Only `std::array` please

Nor like this (although this gets a bit tricky to actually use):

template <class T>
auto operator()() const; // No deduction

C++14 lambdas are fine, but C++20 allows us to implement these cases without hassle.

C++ lambda as std::function in template function

What about simply as follows ?

template <typename F>
auto Context::executeTransient (F const & commands) {
...
auto result = commands(commandBuffer);
...
return result;
}

This way your method accept both standard functions and lambdas (without converting them to standard functions, that is preferable, from the performance point of view (as far as I know)) and the return type is deduced from the use (auto).

In you need to know the R type inside the method, you can apply decltype() to result

     auto result = commands(commandBuffer);

using R = decltype(result);

If you need to know the R type as template parameter of the method, its a little more complex because involve std::declval() and, unfortunately, add redundancy

template <typename F,
typename R = decltype(std::declval<F const &>()(commandBuffer))>
R Context::executeTransient (F const & commands) {
...
R result = commands(commandBuffer);
...
return result;
}

How to invoke a lambda template?

The second definition is a variable template. It does not define the lambda's operator() as a template, but rather takes the parameter pack for the argument types of operator(). The resulting operator() is a regular member function of the instantiated variable's closure type. There is no template argument deduction possible here.

So when you write lamd<int>, the variable gets a closure type with a operator()(int), not something callable with 3 integers.

As mentioned already, you can use a generic lambda instead.

In C++20, if you'd need the lambda's argument types to be named and deduced, you can use the syntax:

auto lamd = []<typename... Pack>(Pack...) {}

This will define the operator as template, accepting a parameter pack, and leave the door open for template argument deduction.

Is possible to invoke a templated lambda with explicit specialization?

It is not the class/variable which is template, but its operator:

testLamb.operator()<int, 4>(4);


Related Topics



Leave a reply



Submit