在未求值上下文的Lambda中用std::declval是否合法?编译器谁正确?
Lambda捕获列表中使用std::declval是否合法?
我有一段代码可通过GCC和MSVC编译,但Clang报错。我在C++标准中未找到相关禁止条款,认为应支持该用法,想明确Clang与GCC/MSVC谁的处理符合标准。
#include <type_traits> void foo() { static_assert(decltype([_=std::declval<int>()]() consteval noexcept { // clang error: declval() must not be used if constexpr (std::is_integral<decltype(_)>::value) { return std::bool_constant<true>(); } else { return std::bool_constant<false>(); } }())::value); }
我将示例扩展为三种情况,不同编译器的表现如下:
- 作为Lambda调用实参:Clang、GCC、MSVC均编译通过
- 作为Lambda捕获:GCC、MSVC编译通过,Clang报错
- 在Lambda体内:Clang、GCC、MSVC均报错
目前明确Lambda体内使用std::declval不合法,外部作为调用实参合法,但捕获列表中是否允许使用尚不明确,特此咨询。
#include <type_traits> auto foo_lambda_argument() { return decltype([](auto _) noexcept { return std::bool_constant<std::is_integral<decltype(_)>::value>(); }(std::declval<int>()))::value; // OK with clang/gcc/MSVC } auto foo_capture_list() { return decltype([_=std::declval<int>()]() noexcept { // OK with gcc/MSVC; clang error: declval() must not be used return std::bool_constant<std::is_integral<decltype(_)>::value>(); }())::value; } auto foo_lambda_body() { return decltype([]() noexcept { auto _=std::declval<int>(); // clang/gcc/MSVC error return std::bool_constant<std::is_integral<decltype(_)>::value>(); }())::value; }
标准分析与结论
根据C++标准,std::declval<T>()的核心限制是不能被求值——它仅允许出现在未求值语境(如decltype、sizeof、if constexpr条件表达式等)中,用于推导类型,而不能产生实际的执行代码。
回到Lambda捕获的场景:这里的Lambda调用完全处于decltype内部,属于未求值语境。Lambda的捕获初始化表达式只会在Lambda对象被构造时求值,但在decltype中查询调用返回类型的过程中,并不会实际构造Lambda对象,因此捕获初始化表达式std::declval<int>()不会被求值,完全符合std::declval的使用规则。
因此,GCC和MSVC的处理是正确的,Clang的报错属于实现错误。
内容的提问来源于stack exchange,提问作者wanghan02
相关产品推荐
相关产品推荐

