Использование функтора на for_each - PullRequest
8 голосов
/ 13 марта 2011

Почему вызов for_each на функторе не обновляется sum::total в конце?

struct sum
{
    sum():total(0){};
    int total;

    void operator()(int element) 
    { 
       total+=element; 
    }
};

int main()
{
    sum s;

    int arr[] = {0, 1, 2, 3, 4, 5};
    std::for_each(arr, arr+6, s);
    cout << s.total << endl; // prints total = 0;
}

Ответы [ 4 ]

12 голосов
/ 13 марта 2011

for_each принимает функтор по значению - поэтому он копируется.Например, вы можете использовать функтор, который инициализируется указателем на внешнюю переменную.

struct sum
{
    sum(int * t):total(t){};
    int * total;

    void operator()(int element)
    {
       *total+=element;
    }
};

int main()
{
    int total = 0;
    sum s(&total);

    int arr[] = {0, 1, 2, 3, 4, 5};
    std::for_each(arr, arr+6, s);
    cout << total << endl; // prints total = 15;
}

Или вы можете использовать возвращаемое значение из for_each

struct sum
{
    sum():total(0){};
    int total;

    void operator()(int element) 
    { 
       total+=element; 
    }
};

int main()
{
    sum s;

    int arr[] = {0, 1, 2, 3, 4, 5};
    s = std::for_each(arr, arr+6, s);
    cout << s.total << endl; // prints total = 15;
}
3 голосов
/ 13 марта 2011

Поскольку s, который вы передаете for_each, является значением. for_each принимает его по значению!

В C ++ 0x вы можете решить эту проблему с помощью for_each as,

int sum  = 0;
std::for_each(arr, arr+6, [&](int n){ sum += n; });
std::cout << sum ;

Выход:

15

Демонстрация на ideone: http://ideone.com/s7OOn


Или вы можете просто написать в самой std::cout:

std::cout<<std::for_each(arr,arr+6,[&](int n)->int{sum += n;return sum;})(0);

Прогон: http://ideone.com/7Hyla

Обратите внимание, что такой различный синтаксис подходит для целей обучения, как работает std::for_each и что он возвращает, но я бы не рекомендовал бы этот синтаксис в реальном коде. : -)


В C ++ вы можете написать пользовательскую функцию преобразования в функторе как

struct add
{
    int total;
    add():total(0){};
    void operator()(int element)  {  total+=element;  }
    operator int() { return total ; }
};

int main()
{
    int arr[] = {0, 1, 2, 3, 4, 5};
    int sum = std::for_each(arr, arr+6, add());
    std::cout << sum;
}

Это немного другая версия от второго решения Эрика: http://ideone.com/vKnmA

3 голосов
/ 13 марта 2011

for_each получает копию вашего функтора по значению.Даже после этого его можно бесплатно скопировать, но он возвращает копию.

OTOH, вы просто пытаетесь заново изобрести std::accumulate, что сделает работу намного проще:

int total = std::accumulate(arr, arr+6, 0);
cout << total << endl; 
0 голосов
/ 14 ноября 2014

Это происходит из-за того, что std :: for_each требует, чтобы функтор передавался по значению.Обходной путь для вашего решения:

struct sum
{
    sum():total(0){};
    int total;
    sum(sum & temp)
    {
        total = temp.total;
    }
    void operator()(int element) 
    { 
       total+=element; 
    }
};

int main()
{
    sum s;

    int arr[] = {0, 1, 2, 3, 4, 5};
    s = std::for_each(arr, arr+6, s);  // result of for_each assigned back to s
    cout << s.total << endl; // prints total = 0;
}
...