【问题标题】:Will I be able to declare a constexpr lambda inside a template parameter?我可以在模板参数中声明一个 constexpr lambda 吗?
【发布时间】:2017-11-13 02:43:39
【问题描述】:

我知道这就像打开潘多拉魔盒,但它并没有停止困扰我。考虑一个简单的例子:

#include <type_traits>

template <auto>
struct Foo: std::false_type { };

template <>
struct Foo<[](){return 1;}()>:std::true_type { };

int main() {
    static_assert(Foo<1>::value);
}

我知道不能在未评估的上下文中声明 lambda,但显然这里不是这种情况。更奇怪的是 clang 5.0.0(我猜,它首先部分支持 constexpr lambda)does compile it

这是编译器错误还是 C++17 允许这样做?

【问题讨论】:

    标签: c++ templates language-lawyer c++17


    【解决方案1】:

    不,这是一个编译器错误。 gcc 7.1 正确拒绝代码。

    [expr.prim.lambda]/2:

    lambda 表达式是一个纯右值,其结果对象称为闭包对象。 lambda 表达式不得出现在未计算的操作数中、模板参数中、别名声明中、typedef 声明中,或在其函数体之外的函数或函数模板的声明中和默认参数。

    从我标记为粗体的部分可以看出,lambda 表达式不能出现在模板参数列表中。

    这在随后的注释中也明确说明:

    [ 注意:目的是防止 lambda 出现在签名中。 — 尾注 ]

    如果我猜的话,我会说这个 bug 的出现是因为从 C++17 开始,lambda 隐含地是 constexpr,这使得它们在编译时表达式中被调用是有效的,比如模板参数。但实际上在模板参数中定义 lambda 仍然是非法的。


    请注意,此限制已在 C++20 中解除。 :)

    【讨论】:

    • 是的,我认为标准委员会的意图是展示它,这就是为什么我对 clang 编译代码感到惊讶的原因。我会稍等片刻,然后接受你的回答。谢谢!
    • @DanielJour 不,抱歉。但这会使元编程更加更加令人困惑:)
    • @W.F. Jup,我引用的段落不见了:) eel.is/c++draft/expr.prim.lambda#2
    • 不错的发现!感谢分享!让我们希望编码人员能够合理地使用它;)
    • 等等!现在可以在 decltype 中声明 lambda? :o
    【解决方案2】:

    在 C++17 中,您可以将指向 lambda 函数的指针作为具有函数指针类型的模板参数传递:

    # include <cassert>
    
    template<int(*fn)()>
    int get_twice()
    {
        return fn() * 2;
    }
    
    int main()
    {
        int result = get_twice <+[]() { return 42; }> ();
        assert(result == 84);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-21
      • 2014-06-07
      • 2016-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多