制作 lambda constexpr 的要求是什么?
What are the requirements to make a lambda constexpr?
有好几次,在代码审查中,我被告知要将 contexpr
添加到某个命名的 lambda 闭包声明中,即我被告知要更改此
auto lam = [<i>捕获列表</i>](<i>args</i>){<i>body</i>}
对此:
constexpr auto lam = [<i>捕获列表</i>](<i>args</i>){<i>body</i>}
因此,我想了解允许将 lambda 闭包声明为 constexpr
的条件是什么,以便我可以自主进行此更改。
Here 我读了
A constexpr variable must satisfy the following requirements:
- its type must be a LiteralType.
- it must be immediately initialized
- the full-expression of its initialization, including all implicit conversions, constructors calls, etc, must be a constant expression
- [a C++20-specific condtion]
我看到第二个条件已得到验证,但我想要一些帮助来理解第一个,尤其是第三个条件。
关于第一个条件,在 LiteralType 页面上,我了解到变量是 LiteralType 就足够了,成为 可能是 cv 限定的 class具有析构函数的类型(怎么可能没有?)并且是闭包类型(上面的lam
就是这种情况),以及所有非静态数据成员和基础 classes 都是非易失性文字类型(我不确定与 lambda 相关的最后一部分)。
最重要的是,我想了解如何通过检查来理解我是否可以制作 lambda constexpr
。
唯一决定 lambda 是否可以 constexpr
的是捕获列表。正文可以是非 constexpr
并且 constexpr
lambda 仍然可以具有像 std::string
这样的参数,它们也不是文字类型。
its type must be a LiteralType.
lambda 的 LiteralType 要求实际上意味着所有捕获的成员也必须是 non-volatile 文字类型。定义一个 lambda 等同于定义一个匿名 struct
,其中捕获的变量是成员。
constexpr int x = 0;
constexpr auto lam = [x](){};
// equivalent to:
struct Lam {
int x;
void operator()() {}
};
constexpr Lam lam2{x};
当我们将 lambda 视为具有调用运算符的 struct
时,所有这些要求的含义也变得显而易见。我们无法捕获 non-literal 类型,因为这需要在此 struct
中存储 non-literal 类型。这在 constexpr
环境中是不可能发生的。
the full-expression of its initialization, including all implicit conversions, constructors calls, etc, must be a constant expression
再一次,这基本上表明捕获变量必须以 constexpr
方式发生。所有捕获的变量必须是constexpr
,否则不会初始化。实际上,constexpr
个变量都是隐式捕获的。 所以这真正的意思是可以在 lambda 没有捕获列表的时候创建 constexpr
,或者可以省略捕获列表。
有好几次,在代码审查中,我被告知要将 contexpr
添加到某个命名的 lambda 闭包声明中,即我被告知要更改此
auto lam = [<i>捕获列表</i>](<i>args</i>){<i>body</i>}
对此:
constexpr auto lam = [<i>捕获列表</i>](<i>args</i>){<i>body</i>}
因此,我想了解允许将 lambda 闭包声明为 constexpr
的条件是什么,以便我可以自主进行此更改。
Here 我读了
A constexpr variable must satisfy the following requirements:
- its type must be a LiteralType.
- it must be immediately initialized
- the full-expression of its initialization, including all implicit conversions, constructors calls, etc, must be a constant expression
- [a C++20-specific condtion]
我看到第二个条件已得到验证,但我想要一些帮助来理解第一个,尤其是第三个条件。
关于第一个条件,在 LiteralType 页面上,我了解到变量是 LiteralType 就足够了,成为 可能是 cv 限定的 class具有析构函数的类型(怎么可能没有?)并且是闭包类型(上面的lam
就是这种情况),以及所有非静态数据成员和基础 classes 都是非易失性文字类型(我不确定与 lambda 相关的最后一部分)。
最重要的是,我想了解如何通过检查来理解我是否可以制作 lambda constexpr
。
唯一决定 lambda 是否可以 constexpr
的是捕获列表。正文可以是非 constexpr
并且 constexpr
lambda 仍然可以具有像 std::string
这样的参数,它们也不是文字类型。
its type must be a LiteralType.
lambda 的 LiteralType 要求实际上意味着所有捕获的成员也必须是 non-volatile 文字类型。定义一个 lambda 等同于定义一个匿名 struct
,其中捕获的变量是成员。
constexpr int x = 0;
constexpr auto lam = [x](){};
// equivalent to:
struct Lam {
int x;
void operator()() {}
};
constexpr Lam lam2{x};
当我们将 lambda 视为具有调用运算符的 struct
时,所有这些要求的含义也变得显而易见。我们无法捕获 non-literal 类型,因为这需要在此 struct
中存储 non-literal 类型。这在 constexpr
环境中是不可能发生的。
the full-expression of its initialization, including all implicit conversions, constructors calls, etc, must be a constant expression
再一次,这基本上表明捕获变量必须以 constexpr
方式发生。所有捕获的变量必须是constexpr
,否则不会初始化。实际上,constexpr
个变量都是隐式捕获的。 所以这真正的意思是可以在 lambda 没有捕获列表的时候创建 constexpr
,或者可以省略捕获列表。