std :: for_each, объект с оператором () перегружен, не поддерживает состояние - PullRequest
0 голосов
/ 11 августа 2011

Пытаясь ответить на этот вопрос, я придумал следующий код:

#include <string>
#include <iostream> 
#include <algorithm>
#include <vector>

class Sizes
{
public:
    void operator() ( std::vector<int> v ) { 
        sizeVec.push_back( v.size() );  
    }
    std::vector<int> sizeVec;
};

void outFunc (int i) {
    std::cout << " " << i;
}
int _tmain(int argc, _TCHAR* argv[])
{
    std::vector<std::vector<int>> twodVec;

    std::vector<int> vec;
    vec.push_back( 6 );
    twodVec.push_back( vec );
    vec.push_back( 3 );
    twodVec.push_back( vec );
    vec.push_back( 8 );
    twodVec.push_back( vec );
    vec.push_back( 3 );
    twodVec.push_back( vec );

    Sizes sizes;
    std::for_each( twodVec.begin(), twodVec.end(), sizes );
    std::for_each( sizes.sizeVec.begin(), sizes.sizeVec.end(), outFunc );

    return 0;
}

Отладка показывает, что вызывается Sizes :: operator () и размер sizeVec увеличивается с каждым вызовом, как и ожидалось. Однако, когда второй std :: foreach называется sizeVec, он пуст ... Я создал работу, связанную с передачей вектора в Sizes, но кто-нибудь знает, что происходит

Ответы [ 3 ]

3 голосов
/ 11 августа 2011

std::for_each принимает функтор по значению , а не по ссылке , поэтому на оригинальный объект это не влияет. Вам нужно сделать:

sizes = std::for_each( twodVec.begin(), twodVec.end(), sizes );
2 голосов
/ 11 августа 2011

Я бы сделал несколько вещей по-другому:

// (1) struct rather than class for functor (as it contains no state).
struct Sizes
{
    // (2) Keep a reference to the vector
    std::vector<int>&    sizeVec;

    Sizes(std::vector<int>& sizeVec): sizeVec(sizeVec) {}

    // (3) The functor can now be const as the the state is external
    void operator() ( std::vector<int> const& v ) const
    {                              //  ^^^^^^  (4) Pass parameter by const reference
                                   //              This avoids an unnecessary copy.
        sizeVec.push_back( v.size() );  
    }
};

std::for_each( twodVec.begin(), twodVec.end(), Sizes(vec) );
                                         //    ^^^^^^^^^^  Call using temporary
                                         //                No need for a Size variable.

Ваш второй for_each и outFunc () можно заменить некоторыми стандартными объектами:

std::copy(sizes.sizeVec.begin(),
          sizes.sizeVec.end(),
          std::ostream_iterator<int>(std::cout, " ")
         );

Второстепенное, хотя и более неясноепримечание: сохранение состояния вне объекта Sizes облегчает преобразование в C ++ 0x лямбду, когда это произойдет в следующем году:

std::for_each( twodVec.begin(), twodVec.end(), Sizes(vec) );

// becomes

std::for_each( twodVec.begin(),
               twodVec.end(), 
               [&vec] ( std::vector<int> const& v ) {  vec.push_back(v.size()); }
             );
2 голосов
/ 11 августа 2011

Фрагменты кода, показанные ниже, процитированы из вашего кода, как это было, когда я писал это.

#include <string>
#include <iostream> 
#include <algorithm>
#include <vector>

class Sizes
{
public:
    void operator() ( std::vector<int> v ) { 

v передается по значению, что может быть довольно неэффективно!Передайте его по ссылке.


        sizeVec.push_back( v.size() );  
    }
    std::vector<int> sizeVec;
};

void outFunc (int i) {
    std::cout << " " << i;
}
int _tmain(int argc, _TCHAR* argv[])

_tmain никогда не был действительной формой main.

Этот код в лучшем случае будеткомпилируется только с компилятором Microsoft.

Кроме того, _tmain не имеет смысла даже с компилятором Microsoft, за исключением одного особого случая при нацеливании на Windows 9x (даже не на цели на Windows 9x в целом).

Почему вы пишете больше для того, чтобы сделать ваш код нестандартным и не пригодным для использования не программистами Windows?

Использовать стандартные main.


{
    std::vector<std::vector<int>> twodVec;

>>, вероятно, будет компилироваться с большинством современных компиляторов, поскольку они поддерживают грядущий C ++ 0x.Но в C ++ 98 / C ++ 03 это недопустимо.Таким образом, для переносимого кода все равно пишите > > (обратите внимание на пробел).


    std::vector<int> vec;
    vec.push_back( 6 );
    twodVec.push_back( vec );
    vec.push_back( 3 );
    twodVec.push_back( vec );
    vec.push_back( 8 );
    twodVec.push_back( vec );
    vec.push_back( 3 );
    twodVec.push_back( vec );

    Sizes sizes;
    std::for_each( twodVec.begin(), twodVec.end(), sizes );

sizes может быть свободно скопировано здесь и фактически передаетсязначение.

Однако std::for_each возвращает копию окончательного результата.

Вы можете присвоить его обратно sizes, даже если это довольно неэффективный способ выполнения действий, когдаФунктор содержит вектор.


    std::for_each( sizes.sizeVec.begin(), sizes.sizeVec.end(), outFunc );

    return 0;

Этот окончательный return 0; не требуется для стандартного main, поскольку он выражает только возвращаемое значение по умолчанию для стандартного main.


}

Приветствия и hth.

...