lambda作为静态成员(lambda as a static member)

2019-06-26 15:35发布

我试图用一个lambda作为一个静态成员,就像这样:

struct A
{
    static constexpr auto F = [](){};
};


int main()
{
    A::F();
    return 0;
}

这是正确的,即使C ++代码11? 在铛,我得到这个错误:

error: constexpr variable 'F' must be initialized by a constant
      expression
    static constexpr auto F = [](){};
                              ^~~~~~

这似乎在铛,lambda表达式不被视为一个常量表达式。 它是否正确? 也许他们还没有完全实现铿锵lambda表达式又因为gcc 4.7似乎允许它作为一个constexpr ,但它给另一个错误:

error: ‘constexpr const<lambda()> A::F’, declared using local type ‘const<lambda()>’, is used but never defined

我不知道,我明白这意味着什么。 它似乎正确地推断拉姆达的类型,但它只是声明它,而不是定义它。 我将如何去界定呢?

Answer 1:

是形成不良的这段代码。 甲constexpr需要变量由常量表达式进行初始化,并[expr.const]p2表示:

一个条件表达式是一个核心常量表达式除非它涉及以下作为一个潜在的评价子表达式中的一个[...]:

  • 一个λ-表达

GCC因此不正确,接受此代码。

下面就来给一个类拉姆达类型的静态数据成员的一种方式:

auto a = []{};
struct S {
  static decltype(a) b;
};
decltype(a) S::b = a;


Answer 2:

你可以把它的工作,在铛3.4,只要在lambda不捕获任何东西。 这个想法是直接从Pythy 。

#include <type_traits>
#include <iostream>
template<typename T>
auto address(T&& t) -> typename std:: remove_reference<T> :: type *
{
        return &t;
}

struct A
{
        static constexpr auto * F = false ? address(

                [](int x){ std:: cout << "It worked. x = " << x << std:: endl;

                }
        ) : nullptr; // a nullptr, but at least its *type* is useful
};


int main()
{
    (*A::F)(1337); // dereferencing a null. Doesn't look good
    return 0;
}

这里有两个可能引起争议位。 首先,有一个事实,即A::Fconstexpr ,但它在其定义的λ。

这应该是不可能的吧? 编号A三元表达式b ? v1 : v2 b ? v1 : v2可以是constexpr ,而不需要所有三个bv1v2constexpr 。 这是足以仅仅是bconstexpr与剩下的两个(取决于是否一个沿btruefalse下面。 bfalse ,而这种选择的最后一部分?:nullptr

换句话说false ? a_non_constexpr_func() : a_constexpr_func() false ? a_non_constexpr_func() : a_constexpr_func()是一个constexpr 。 这似乎是在铛解释反正。 我希望这是什么标准。 如果没有,我也不会说,铛“不应该接受这个”。 这似乎是规则的有效放松。 的未计算的部分?:是未计算的,因此它constexpr -ness不应该的问题。

总之,假设这是确定的,这给了我们一个nullptr正确类型的,即一个指向拉姆达的类型。 第二有争议位是(*A::F)(1337); 当我们取消引用空指针。 但是,它是由辩称页上面链接是没有问题的:

看来,我们derefencing一个空指针。 请记住,在C ++解引用一个空指针时,当存在一个左值到右值转换发生未定义的行为。 然而,由于非捕获拉姆达闭合为不带任何成员的对象几乎总是执行,不确定的行为永远不会发生,因为它不会访问任何成员。 它的极不可能的,非捕获拉姆达闭合可以实现另一种方式,因为它必须可以转换成一个函数指针。 但该库静态断言闭包对象是空的,以避免任何可能的不确定的行为。



文章来源: lambda as a static member