This pointer capture in a lambda wrapper around the recursive function
I have a class template Wrap<T>
with a recursive member function test(int)
that I want to pass to the STL algorithm using a lambda ( std::accumulate
in the code below).
If I use the default capture list =
and do a recursive meber function static
, everything is fine and get the result I want.
However, if I make it a non-static member function, both Visual C ++ and gcc 4.7.2 complain about unified this
-flow, unless I get my recursive call like this->test()
.
#include <algorithm>
#include <iostream>
#include <vector>
template<typename T>
struct Wrap
{
static int test1(int depth)
{
std::vector<int> v = { 0, 1, 2, 3 };
return depth == 0? 1 : std::accumulate(v.begin(), v.end(), int(0), [=](int sub, int const&) {
return sub + test1(depth - 1);
});
}
int test2(int depth)
{
std::vector<int> v = { 0, 1, 2, 3 };
return depth == 0? 1 : std::accumulate(v.begin(), v.end(), int(0), [=](int sub, int const&) {
return sub + /*this->*/test2(depth - 1);
});
}
};
int main()
{
std::cout << Wrap<int>::test1(0) << "\n"; // 1
std::cout << Wrap<int>::test1(1) << "\n"; // 4
std::cout << Wrap<int>::test1(2) << "\n"; // 16
Wrap<int> w;
std::cout << w.test2(0) << "\n"; // 1
std::cout << w.test2(1) << "\n"; // 4
std::cout << w.test2(2) << "\n"; // 16
}
Conclusion to LiveWorkSpace :
source.cpp: In instantiation of 'int Wrap<T>::test2(int) [with T = int]':
source.cpp:32:26: required from here
source.cpp:19:74: error: missing initializer for member 'Wrap<T>::test2(int) [with T = int]::<lambda(int, const int&)>::__this' [-Werror=missing-field-initializers]
Uncommenting the snippet /*this->/*
gives the same result as for a static member function.
Why do I need to qualify the recursive call with this->
?
source to share
I believe this is a bug in GCC 4.7.2. The warning reads:
missing initializer for member 'Wrap<T>::test2(int) [with T = int]::<lambda(int, const int&)>::__this'
This means that the compiler recognizes a pointer this
to be captured, and the generated closure contains a pointer to it, but that pointer is not initialized in the closure's constructor.
This is supported by the fact that trying to access / modify a member variable (which is not present in your example, but can easily be added) causes a runtime error. For example this does not show the output on liveworkspace.org
#include <algorithm>
#include <iostream>
#include <vector>
template<typename T>
struct Wrap
{
int test2(int depth)
{
m_test++;
std::vector<int> v = { 0, 1, 2, 3 };
return depth == 0? 1 : std::accumulate(
v.begin(), v.end(), int(0), [=](int sub, int const&) {
return sub + /*this->*/test2(depth - 1);
});
}
int m_test = 0;
};
int main()
{
Wrap<int> w;
std::cout << w.test2(2) << "\n"; // 1
}
This code compiles fine with Clang 3.2 and VS2012, which seems to confirm there is a bug.
source to share