Oer*_*ted 9 c++ constant-expression callable-object constexpr-function
问题标题的措辞可能不正确,我会很乐意根据您的建议进行修复。
我的问题可以用这个片段来说明:
#include <array>
template <typename Callable>
constexpr auto make_array_ok(Callable callable) {
return std::array<int, callable()>{};
};
// constexpr auto make_array_bad(std::size_t s)
// {
// return std::array<int,s>{};
// };
int main(int argc, char**) {
static_cast<void>(argc);
auto size = []() { return std::size_t{42}; };
// fails to compile -- as I expected
// auto size_dyn = [argc]() { return std::size_t(argc); };
// auto a = make_array_ok(size_dyn);
// also fails to compile -- but why?
// auto size_capt = [arg = size()]()constexpr{return arg;};
// auto a = make_array_ok(size_capt);
auto a = make_array_ok(size);
return a.size();
}
Run Code Online (Sandbox Code Playgroud)
在需要常量表达式的情况下,constexpr 函数参数被认为不可用(因为 constexpr 函数可以在运行时使用运行时参数调用),因此make_array_bad编译失败是很常见的。但是在什么规则下可以make_array_ok编译(当与返回 lambda 一起使用时42)?
我怀疑这是因为operator()从 C++17 开始默认 lambda 是 constexpr,但我在 cppreference 中没有找到有关 constexpr 函数的 有关其参数在常量表达式中的可用性的详细信息。
但为什么它不适用于该size_capt版本呢?
(这是对原始问题的回答。)
该代码起作用的原因在注释中,但分享可以遵循的思维过程以获得答案可能很有用:
std::array<int, callable()>编译,callable()必须在编译时知道,callable是一个constexpr可调用的(例如constepxr函数或constexpr operator()lambda 的);callable,问题就变成了:为什么是operator() constexprfor[]() { return std::size_t{42}; }而不是 for [argc]() { return std::size_t(argc); }?答案是另一个答案:D关于更新的问题,我认为这一切都归结为一个更简单的例子:为什么以下内容无法编译?
#include <array>
constexpr auto lambda = [arg = 0]() constexpr { return arg; };
constexpr auto make_array(decltype(lambda) callable) {
return std::array<int, callable()>{};
};
Run Code Online (Sandbox Code Playgroud)
where0绝对是一个常量表达式,就像 一样size(),但会减少怀疑的空间。
关键在于函数参数不是constexpr,从某种意义上说,跨函数边界它们会失去constexpr本质,因此即使是lambda 的状态,它是对象的一部分,而不是其类型的一部分(就像0给Foo{}定的一样struct Foo { int i{0}; };,但是与嵌入在类型本身中的a 的大小不同std::array,不能在常量表达式中使用。
第一个 lambda 是隐式 constexpr,而第二个 lambda 不是。这可以从lambda 表达式的文档中看到:
| 说明符 | 影响 |
|---|---|
| constexpr (C++17 起) | 显式指定这operator()是一个 constexpr 函数。如果operator()满足所有 constexpr 函数要求,即使 constexpr 不存在也会如此operator()。constexpr |
由于operator()for 第一个 lambda 满足constexpr 函数的所有要求,因此它operator()隐式是 constexpr。
| 归档时间: |
|
| 查看次数: |
678 次 |
| 最近记录: |