I was playing around with polymorphic variadic lambdas on Clang and noticed that Clang doesn't like this one
#include <iostream>
int main() {
auto append = [](auto &&cnt, auto &&me,
auto &&a, auto &&p1, auto &&...p) -> decltype(auto)
{
if(sizeof...(p) > cnt)
return me(++cnt, me, a << p1, p..., 0);
return a;
};
append(0, append, std::cout, 1, 2, 3, 4);
}
It's intended to putput "1234". A 0 is appended to the parameter list (and in turn one of the parameters from the front is taken away each time) and a counter watches when we need to stop because we would be hitting a dummy 0
.
But Clang complains about
fatal error: recursive template instantiation exceeded maximum depth of 256
In its backtract, most of the function frames are
main.cpp:6:20: note: in instantiation of function template specialization 'main()::<anonymous class>::operator()<int &, <lambda at main.cpp:4:19> &, std::basic_ostream<char> &, int &, int &, int &, int>' requested here
return me(++cnt, me, a << p1, p..., 0);
^
This seems like a recursive function template that calls itself, and I can't see the infinite template instantiation madness. Can someone please shed some light? Does the Standard perpahs forbid recursion like that for lambdas?
A recursive lambda expression is the process in which a function calls itself directly or indirectly is called recursion and the corresponding function is called a recursive function. Using a recursive algorithm, certain problems can be solved quite easily.
But a lambda cannot be recursive, it has no way to invoke itself. A lambda has no name and using this within the body of a lambda refers to a captured this (assuming the lambda is created in the body of a member function, otherwise it is an error).
Creating a Lambda Expression in C++auto greet = []() { // lambda function body }; Here, [] is called the lambda introducer which denotes the start of the lambda expression. () is called the parameter list which is similar to the () operator of a normal function.
constexpr lambda expressions in C++ Visual Studio 2017 version 15.3 and later (available in /std:c++17 mode and later): A lambda expression may be declared as constexpr or used in a constant expression when the initialization of each data member that it captures or introduces is allowed within a constant expression.
That should be [dcl.spec.auto]/11 (quoting n3797)
If the type of an entity with an undeduced placeholder type is needed to determine the type of an expression, the program is ill-formed. Once a
return
statement has been seen in a function, however, the return type deduced from that statement can be used in the rest of the function, including in otherreturn
statements.
So, by reverting the return-statements, the return type deduction can succeed:
#include <iostream>
int main() {
auto append = [](auto &&cnt, auto &&me,
auto &&a, auto &&p1, auto &&...p) -> decltype(auto)
{
if(sizeof...(p) <= cnt)
return a;
return me(++cnt, me, a << p1, p..., 0);
};
append(0u, append, std::cout, 1, 2, 3, 4);
}
Live example
My guess would be it's looping forever trying to deduce your return type. When it sees return me( ... )
, it tries to figure out what THAT function's return is, which is also auto
which requires figuring out what return me( ... )
is and so on.
Maybe try
if(sizeof...(p) <= cnt) return a;
return me(++cnt, me, a << p1, p..., 0);
or try decltype(a)
as the return type.
I don;t have a 1y compiler handy at the moment, or I'd be able to say for certain.
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