c++ - 可以在 C++20 中的 `decltype` 或 `sizeof` 表达式中定义类型吗?
问题描述
由于 C++20 lambda 函数允许在未计算的上下文中使用,特别是它们应该被允许在decltype
和sizeof
表达式中使用。
反过来,lambda 可以在它们的主体中定义一些类型,并可能返回这些类型的对象,例如:
using T = decltype( []{ struct S{}; return S{}; } );
[[maybe_unused]] constexpr auto N
= sizeof( []{ struct S{}; return S{}; } );
Clang 接受此代码,但 GCC 发出错误:
error: types may not be defined in 'decltype' expressions
1 | using T = decltype( []{ struct S{}; return S{}; } );
error: types may not be defined in 'sizeof' expressions
4 | = sizeof( []{ struct S{}; return S{}; } );
演示:https ://gcc.godbolt.org/z/9aY1KWfbq
哪一个编译器在这里?
解决方案
在P0315R4中删除的未评估上下文中对 lambdas 的限制意味着这是不被禁止的(尽管是极端情况),因此可以说 GCC 在这里有一个错误。特别是本文中的以下讨论与此处相关:
此外,在核心反射器上提出了一些关于重新声明的问题,如下所示:
template <int N> static void k(decltype([]{ return 0; }())); template <int N> static void k(decltype([]{ return 0; }())); // okay template <int N> static void k(int); // okay
这些应该是有效的重新声明,因为 lambda 表达式是经过计算的,它们的主体中既不包含模板参数,也不是包含模板参数的完整表达式的一部分。因此,lambda-expression 不需要出现在函数的签名中,其行为与此等价,无需任何特殊措辞:
struct lambda { auto operator()() const { return 0; } }; template <int N> static void k(decltype(lambda{}())); template <int N> static void k(decltype(lambda{}())); // okay today template <int N> static void k(int); // okay today
同样的论点也适用于 OP 的示例,并且(可以说)“行为与此等效,不需要任何特殊措辞”:
struct lambda { auto operator()() const { struct S{}; return S{}; } };
using T = decltype(lambda{});
[[maybe_unused]] constexpr auto N = sizeof( []{ struct S{}; return S{}; } );
请注意,这sizeof
更简单,因为您正在查询无捕获 lambda 的闭包类型的大小,而不是本地 struct 的大小S
。