Passing Lambdas as a Template Parameter

I've been playing around with this piece of code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
#include <string>
#include <algorithm>

template <void(*funky)(const std::string&)>
void callback()
    {funky("Hello World!");}

void funct(const std::string& s)
    {std::cout << s << '\n';}

int main() {
    using namespace std;

    constexpr auto lambda =
        [](const std::string& s){
            std::string s2(s);
            std::reverse(s2.begin(), s2.end());
            std::cout << s2 << '\n';
        }
    ;

    callback<funct>();
    callback<lambda>();

    return 0;
}


But when I try to build it, I get this error on line 24:
could not convert template argument 'lambda'
to 'void (*)(const string&) {aka void (*)(const std::basic_string<char>&)}'|


I thought the lambda expression I wrote would decay to a function pointer matching the template parameter. I can guess that the constexpr qualifier might have changed the type, but without it my compiler complains that lambda needs to be declared as constexpr...

So is there a way to pass lambda expressions as template parameters?

Edit:
Without having to use std::function
Last edited on
So is there a way to pass lambda expressions as template parameters?

This would be an abuse of templates, in my opinion.

Why not simply use function pointers instead? By the way, std::function is exactly what you would use for clean, understandable code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
#include <string>
#include <algorithm>
#include <functional>

void callback(const std::function<void(const std::string &)> &funky)
    {funky("Hello World!");}

void funct(const std::string& s)
    {std::cout << s << '\n';}

int main() {
    using namespace std;

    constexpr auto lambda =
        [](const std::string& s){
            std::string s2(s);
            std::reverse(s2.begin(), s2.end());
            std::cout << s2 << '\n';
        }
    ;

    callback(funct);
    callback(lambda);

    return 0;
}

Oh, I did not realize it was an abuse of templates. I thought it would be nice to have the option to pass a lambda expression directly as a template parameter.

I suppose I'll stick with std::function, then. Thanks for the insight.
I thought the lambda expression I wrote would decay to a function pointer

template argument deduction doesn't attempt implicit conversions, but even if you forced it by instantiating callback<+lambda>(), it wouldn't work because non-type template argument that is a function pointer must point to a function with external linkage: in order to be a part of the type, it must be a compile-time constant. What you get when decaying a lambda into a pointer isn't one. Also, the conversion operator isn't constexpr.

Why not parametrize your callback on the type of the functor, rather than its address?
Oh, I did not realize it was an abuse of templates.

I am not an authority, that was only my opinion.

Here's a relevant StackOverflow thread to follow up on Cubbi's suggestion:
http://stackoverflow.com/questions/1174169/function-passed-as-template-argument
Topic archived. No new replies allowed.