I try following code to check if template are instantiated in unevaluated context:
#include "foo.h"
template <typename T = int>
constexpr auto f(int)
// from declaration, foo(std::declval<T>()) is allowed.
// Even if definition would produce errors if instantiated
-> decltype(foo(std::declval<T>()), void(), 42)
{
return 42;
}
static_assert(f(0) == 42);
with foo
as template function: (No errors)
template <typename ...Ts>
void foo(Ts... args)
{
static_assert(sizeof...(Ts) == 42, "!");
((args += ""), ...);
}
Demo
with foo
as regular functor: (No errors)
struct Foo
{
template <typename ...Ts>
void operator ()(Ts... args) const
{
static_assert(sizeof...(args) == 42, "!");
((args += ""), ...);
}
} foo;
Demo
But foo
as lambda: (Error)
auto foo = [](auto... args)
{
static_assert(sizeof...(args) == 42, "!"); // Triggers
((args += ""), ...); // spotted as invalid: int += const char*
};
Demo
Is it normal that operator()
of lamdba is instantiated?
gcc/clang have same behavior.
The lambda case is actually different than the others! You don't specify a return type for the lambda, so it is deduced. For the deduction to happen the lambda has to be instantiated.
This is not the case for the function object, since there you specified the return type to be void
. Changing the lambda to return void
to avoid the deduction makes gcc/clang happy. :)
auto foo = [](auto... args) -> void // <---
{
static_assert(sizeof...(args) == 42, "!");
((args += ""), ...);
};
And if you change the function object as follows:
struct Foo
{
template <typename ...Ts>
auto operator ()(Ts... args) const // <---- placeholder as return type
{
static_assert(sizeof...(args) == 42, "!");
((args += ""), ...);
}
} foo;
it does also instantiate Foo::operator()
to be able to deduce the return type.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With