Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Pass lambda to template parameter

How to pass lambda as template parameter.
For example this code

template<void (*callback)()>
void function() {
    callback();
}

int main() {
    function<[]() -> void { std::cout << "Hello world\n"; }>();
}

fails with error "invalid template argument for 'function', expected compile-time constant expression".
What I'm doing wrong.

Edit
I want to implement something like this

template<typename T,
        T (*deserializer)(buffer *data),
        void (*serializer)(T item, buffer *data)>
class Type {
public:
    T item;

    Type(T item) : item(item) {
    }

    Type(buffer *data) {
        deserialize(data);
    }

    void serialize(buffer *data) {
        serializer(item, data);
    }

    void deserialize(buffer *data) {
        deserializer(data);
    }
};

typedef Type<int, [](buffer* data) -> int { return -1; }, [](int item, buffer* data) -> void {}> IntType

typedef Type<long, [](buffer* data) -> long { return -1; }, [](long item, buffer* data) -> void {}> LongType
like image 379
KoHcoJlb Avatar asked Feb 01 '17 18:02

KoHcoJlb


1 Answers

Lambdas in C++14, including their conversion to function pointers, are not constexpr.

In C++17, this is going to change. There are no stable compilers with that feature implemented that I'm aware of (if you find one, can you mention it in the comments below?).

At that point

constexpr auto tmp = []() -> void { std::cout << "Hello world\n"; };
function<+tmp>();

will definitely work. I am uncertain if

function<+[]() -> void { std::cout << "Hello world\n"; }>()

would work; there are some rules about lambdas in unevaluated contexts and inside template argument lists that may be separate from the constexpr lambda problem and may apply here.

We can hack it in C++14.

Create a template class that stores a static copy of a lambda and exposes a static function with the same signature (f_ptr) that calls that static copy of a lambda.

Instantiate it once globally with your lambda.

Pass a pointer to the f_ptr to your template.

So:

template<class L> struct stateless; // todo
template<class L> stateless<L> make_stateless(L l){return std::move(l);}

auto foo = make_stateless( []() -> void { std::cout << "Hello world\n"; } );

function< &foo::f_ptr >();

this is almost certainly not what you want.

like image 193
Yakk - Adam Nevraumont Avatar answered Oct 11 '22 12:10

Yakk - Adam Nevraumont