Benedetto
Benedetto

Reputation: 749

consteval lambda with ignored parameter doesn't compile

I have a lambda that ignores its int parameter and always returns a constant. If I mark it consteval, compilation fails because. The compiler complains about invoking the consteval lambda with a non-const parameter. But what does the parameter has to do with the lambda?

From CompilerExplorer:

source:3:16: error: the value of 'i' is not usable in a constant expression 5 | lambda(i);

void bar (auto lambda, int start, int end) {
    for (int i=start; i<end; ++i) {
        lambda(i);
    }
}

int main( )
{
    auto foo = [] (int) consteval { return 2;};

    bar(foo, 1, 9);

    return 0;
}

Upvotes: 6

Views: 298

Answers (3)

303
303

Reputation: 4732

Another way would be to make bar an immediate function. Altough, the usability of an immediate function returning void is rather limited.

consteval void bar(auto lambda, int start, int end) {
    for (int i = start; i < end; ++i) {
        lambda(i);
    }
}

int main() {
    bar([](int) consteval { return 2; }, 1, 9);
}

Upvotes: 0

Alan
Alan

Reputation: 1

One way to solve this(and the simplest) is to change the parameter type of the lambda to int& so that it doesn't need to read the value, as shown below:

int main( )
{//-------------------v------------------------->reference added
    auto foo = [] (int&) consteval { return 2;};

    bar(foo, 1, 9);

    return 0;
}

Working demo

Here is another contrived example that has similar behavior:

template<typename T>
consteval int func(const T) //note NO REFERENCE HERE
{
    return std::is_integral<T>::value;;
}

template<typename T>
//-----------------------v----->note the reference here
consteval int bar(const T&)
{
    return std::is_integral<T>::value;;
}

int main()
{
    
    int p = 2;
    //constexpr int d = func(p); //doesn't work
    constexpr int f = bar(p); //works

}

Contrived example demo

Upvotes: 2

Aykhan Hagverdili
Aykhan Hagverdili

Reputation: 29985

You can also add an explicit check. Not the most elegant solution, but yeah:

#include <type_traits>

void bar(auto lambda, int start, int end) {
    for (int i = start; i < end; ++i) {
        if constexpr (std::is_invocable_v<decltype(lambda)>) {
            lambda();
        } else {
            lambda(i);
        }
    }
}

int main() {
    bar([] () consteval { return 2; }, 1, 9);
    bar([](int) { return 2; }, 1, 9);

    return 0;
}

Upvotes: 0

Related Questions