3

我有一个Wrap<T>带有递归成员函数的类模板test(int),我想将它传递给带有 lambda 的 STL 算法(std::accumulate在下面的代码中)。

如果我使用默认的捕获列表=,并创建我的递归成员函数static,一切都很好并得到我想要的结果。

但是,如果我将其设为非静态成员函数,Visual C++ 和 gcc 4.7.2 都会抱怨一个未初始化的this-pointer,除非我将递归调用限定为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->

4

1 回答 1

3

我相信这是 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 很好地编译,这似乎证实了一个错误的存在。

于 2013-01-19T14:23:42.297 回答