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
returnstatement 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 otherreturnstatements.
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