Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can lambdas be used as non-type template parameter?

Is the following code legal?

template <auto Lambda>
struct A {};

int main () {
  auto lmb = [](int i){return i*i;};
  A<lmb> a;
  return 0;
}

I noticed that g++ compiles it fine, while clang++ returns error: a non-type template parameter cannot have type '(lambda at main.cpp:...)'.

like image 454
DarioP Avatar asked Jun 11 '20 12:06

DarioP


1 Answers

Can lambdas be used as non-type template parameter?

Yes, with implementations that has implemented P0732R2 - Class types in non-type template parameters but clang++ has not implemented it yet.

Source: https://en.cppreference.com/w/cpp/compiler_support


Note that the lambda needs to be at least constexpr (which it is by default):

When this specifier is not present, the function call operator will be constexpr anyway, if it happens to satisfy all constexpr function requirements.

You can however add constexpr to get an error on the lambda itself instead of when using it as a template parameter. As a side note: You can also specify it to be consteval to make it work as a non-type template parameter.

A stateful lambda can be constexpr:

constexpr auto lmb1 = [](int i) {
    static int x = 0;
    return i*i + ++x;
};

while a lambda capturing by reference, or capturing by copy and mutating (mutable), can not. Capturing by copying a constexpr is ok though.

Generic lambdas may be constexpr too:

constexpr auto gen_lmb = []<typename T>(T& val) {
   val += val;
   return val;
};

template <auto Lambda>
struct A {
    template<typename T>
    void doit(T&& arg) {
        std::cout << Lambda(arg) << '\n';
    }
};

//...

A<gen_lmb> ginst;

int v = 1000;
ginst.doit(v);
ginst.doit(std::string("foo "));
std::cout << v << '\n';
2000
foo foo
2000
like image 139
Ted Lyngmo Avatar answered Sep 20 '22 03:09

Ted Lyngmo