c++ 不编译具有忽略参数的常量lambda

wmvff8tz  于 2022-11-19  发布在  其他
关注(0)|答案(3)|浏览(147)

我有一个lambda忽略了它的int参数,总是返回一个常量。如果我把它标记为consteval,编译就会失败,因为。编译器会抱怨用一个非常数的参数调用consteval lambda。但是这个参数和lambda有什么关系呢?
CompilerExplorer开始:
来源:3:16:错误:'i'的值无法在常数运算式中使用5| λ(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;
}
8yoxcaq7

8yoxcaq71#

解决这个问题的一种方法(也是最简单的)是将lambda的参数类型改为int&,这样就不需要读取值,如下所示:

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

    bar(foo, 1, 9);

    return 0;
}

Working demo
下面是另一个具有类似行为的人为示例

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

41ik7eoe

41ik7eoe2#

您还可以添加一个显式检查。这不是最好的解决方案,但确实是:

#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;
}
ctrmrzij

ctrmrzij3#

另一种方法是将bar设为立即数函数。尽管如此,返回void的立即数函数的可用性相当有限。

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);
}

相关问题