Code as below or on godbolt compiles with gcc and MSVC but fails with clang. I couldn't find if/where it is forbidden in the standard. In my opinion it should be supported.
So who is correct on this, clang or 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);
}
The example could be expanded into 3 cases as below or on godbolt:
- as lambda call argument: OK with clang/gcc/MSVC
- as lambda capture: OK with gcc/MSVC, error with clang
- in lambda body: error with clang/gcc/MSVC
So it seems clear that it is not legal in lambda body but legal outside as caller argument. It is not clear if it is allowed in capture list.
#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;
}
language-lawyer
tag – Eyestalkstd::declval()
is not aconstexpr
function. See: en.cppreference.com/w/cpp/utility/declval – Demaggiostatic_assert
is aunevaluated context
. The expression in thestatic_assert
is evaluated at compile time.std::declval()
cannot be used in the evaliated context - thus an error. – Demaggiodeclval
, even in an unevaluated context. The specific error you're running into is there in the library code to stop people from trying to actually call the function. GCC gives me the same error if I try to putif (std::declval<int>() == 0)
into an unevaluated lambda. – Complyif (std::decval<int>()==0)
is obviously a hard error while the example in the post is not. I just want to use the simplest example to show what the problem might be even though it's a bit silly. But I think it is still a valid use case. The reason why I come up with this strange thing is that MSVC has some other compiler bug if _ is lambda parameter and we are developing a cross-platform software. – Smoothspokenif
case is using the result of calling the function, just like how your code is using it to initialize a capture. I don't see how they're different conceptually. If that doesn't float your boat, though,auto x = std::declval<int>();
is the same thing, and that's almost exactly what your capture is doing behind the scenes. Either way, it's up to the standard to handle all of these. – Comply