У меня есть шаблон класса Wrap<T>
с рекурсивной функцией-членом test(int)
что я хочу перейти на алгоритм STL с лямбда (std::accumulate
в коде ниже).
Если я использую список захвата по умолчанию =
и сделай мою рекурсивную функцию meber static
, все в порядке и получить результат, который я хочу.
Однако, если я сделаю это нестатической функцией-членом, и Visual C ++, и gcc 4.7.2 пожалуются на унифицированную this
указатель, если я не квалифицирую свой рекурсивный вызов как 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
}
Выход на 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]
Раскомментировать /*this->/*
кусок, дает тот же результат, что и для статической функции-члена.
Почему мне нужно квалифицировать мой рекурсивный вызов this->
?
Я считаю, что это ошибка GCC 4.7.2. Предупреждение говорит:
missing initializer for member 'Wrap<T>::test2(int) [with T = int]::<lambda(int, const int&)>::__this'
Это означает, что компилятор распознает this
указатель должен быть захвачен, и сгенерированное замыкание действительно содержит указатель для него, но этот указатель не инициализируется в конструкторе замыкания.
Это подтверждается тем фактом, что попытка получить доступ / изменить переменную-член (которая отсутствует в вашем примере, но может быть легко добавлена) вызывает ошибку во время выполнения. Например, это не показывает вывод на 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
}
Этот код прекрасно компилируется с Clang 3.2 и VS2012, что, похоже, подтверждает наличие ошибки.
Других решений пока нет …