3

ラムダ(以下のコード)を使用してSTLアルゴリズムに渡すWrap<T>再帰メンバー関数を含むクラステンプレートがあります。test(int)std::accumulate

のデフォルトのキャプチャリストを使用し=、再帰的なmeber関数を作成するとstatic、すべて問題なく、必要な結果が得られます。

ただし、これを非静的メンバー関数にするとthis、再帰呼び出しをとして修飾しない限り、VisualC++とgcc4.7.2の両方が単一化されたポインターについて文句を言い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

これはGCC4.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 に答える