LINUX.ORG.RU

[C++][STL][for_each] Почему не работает?

 ,


0

0

Задача: создать класс «ячейка». Он имеет размеры (длину; длину и ширину; длину, ширину и высоту — в зависимости от количества измерений) и объём (1*1*длина; 1*длина*ширина или высота*длина*ширина, опять же в зависимости от количества измерений). В конструктор передаётся vector с размерами. При этом автоматически считается объём.

Моя реализация:

class Cell
{
    vector<double> dimensions;		//массив размеров ячейки по осям (r)
    double volume;		//объём (ν)
    void calcSize(double r)
    {
      volume*=r;
    }
public:
    Cell(vector<double> inputDimensions) {
        dimensions=inputDimensions;
	volume=1;
	for_each(dimensions.begin(), dimensions.end(), calcSize); //это строка 44
    }
    //...
};

Ошибка такая:

./main.cpp: In constructor ‘Cell::Cell(std::vector<double, std::allocator<double> >&)’:
./main.cpp:44: ошибка: нет соответствующей функции для вызова ‘for_each(__gnu_cxx::__normal_iterator<double*, std::vector<double, std::allocator<double> > >, __gnu_cxx::__normal_iterator<double*, std::vector<double, std::allocator<double> > >, <unresolved overloaded function type>)’
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.4.3/../../../../include/c++/4.4.3/bits/stl_algo.h:4194: замечание: претенденты: _Funct std::for_each(_IIter, _IIter, _Funct) [with _IIter = __gnu_cxx::__normal_iterator<double*, std::vector<double, std::allocator<double> > >, _Funct = void (Cell::*)(double)]

Что не так? Использовать for не хочется. Не модно.

★★★★★

Последнее исправление: Obey-Kun (всего исправлений: 5)

попробуй

size->begin(), size->end()

dimon555 ★★★★★
()

> Использовать for не хочется. Не модно.

Ну только если действительно за «модой» гнаться...

for_each же не телепат, в отличие от нас - прибиндь calcSize к this.

const86 ★★★★★
()
Ответ на: комментарий от const86

> прибиндь calcSize к this

что это значит? :/

size->begin(), size->end()

по-моему, это точно работать не будет... я кстати вместо size поставил dimensions, а то путаница имела место быть

Obey-Kun ★★★★★
() автор топика

[гонюсь-за-модой-mode]

class Cell
{
public:
  Cell(std::vector<double>& sizes)
  {
    this->sizes = sizes;
    std::for_each(sizes.begin(), sizes.end(), calculate_size);
    volume = calculate_size.GetResult();
  }
  
private:
  class Multiplier
  {
    double result;
    
  public:
    Multiplier()
      : result(1.0)
    {
    }
    
    void operator() (double size)
    {
      result *= size;
    }

    double GetResult() const
    {
      return result;
    }
  } calculate_size;

private:
  std::vector<double> sizes;
  double volume;
};
[/гонюсь-за-модой-mode]

Raving_Zealot ★★
()
Ответ на: комментарий от Raving_Zealot

не очень понимаю в целом :/

это функатор вводится?

и что есть this?

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от RedPossum

я понял. я не знаю, что есть this и не нашёл понятной документации по нему на великомогучем, не подскажете что-нибудь? или просто вкратце объясните.

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от Raving_Zealot

Объясните мне вот какой момент: накой foreach передавать начало и конец коллекции? Я себе представлял, что foreach работает для _всей_ коллекции сразу, т.е. должен быть синтаксис вроде

 for_each(vector, f) 
В крайнем случае, можно определить перегруженную функцию с аргументами начала и конца перебора.

annoynimous ★★★★★
()
Ответ на: комментарий от Obey-Kun

Если коротко, то this - это указатель на экземпляр класса для которого вызывается метод. Любой метод класса на самом деле принимает всегда на один аргумент больше, чем ты пишешь. Первый «невидимый» аргумент как раз и есть this.

Тоеть если ты пишешь

class Cell{
//...
   void calcSize(double r){
   //...
   }
//...
}

То, на самом деле, имеется ввиду

class Cell{
//...
   void calcSize(Cell* this, double r){
   //...
   }
//...
}

Естественно, что такую функцию с двумя аргументами в твоем for_each использовать нельзя, так как там функция должна применяться каждый раз к одному double.

anonymous
()
Ответ на: комментарий от zJes

Это я понимаю. Зачем это делать аргументом функции, если foreach — это более абстрактная сущность. Коллекция, которую перебирают, очевидно уже имеет итератор для перебора и указатели на начало и конец.

annoynimous ★★★★★
()
Ответ на: комментарий от annoynimous

Да я согласен :) Шутка была. Я вообще не понимаю нужности данной реализации форича.

zJes ★★
()

Используйте mem_fun. А еще лучше - for :)

#include <vector>
#include <functional>
#include <algorithm>
#include <iostream>

using namespace std;

class Cell
{
        vector<double> dimensions;      //массив размеров ячейки по осям (r) 
        double volume;      //объём (ν) 
        void calcSize(double r)
        {
                volume*=r;
        }
        public:
                Cell(vector<double> inputDimensions) {
                        dimensions=inputDimensions;
                        volume=1;
                        for_each(dimensions.begin(), dimensions.end(), bind1st(mem_fun(&Cell::calcSize), this));
                        cout << "Dimmension: " << volume << endl;
                }
};

int main(int argc, char *argv[])
{
        vector<double> t;
        t.push_back(2);
        t.push_back(3);
        t.push_back(4);
        t.push_back(5);

        Cell cell(t);

        return 0;
}

rymis ★★
()
Ответ на: комментарий от rymis

Используйте mem_fun. А еще лучше - for :)

Ладно, не мудрствуя лукаво использую for.

public:
    Cell(vector<double> inputDimensions, vector<NearCell> inputNearCells) {
        dimensions=inputDimensions;
	nearCells=inputNearCells;
        volume=1;
        for (int i=0; i<dimensions.size(); ++i) {
            volume*=dimensions[i];
        }
Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от annoynimous

foreach — это более абстрактная сущность

именно поэтому: в данном случае это не перебор элементов одной коллекции, а перебор элементов между двумя итераторами. более абстрактная сущность, ага

jtootf ★★★★★
()
Ответ на: комментарий от JackyTreehorn

SICP

Map является важным конструктом, не только потому, что она фиксирует общую схему, но и потому, что она повышает уровень абстракции при работе со списками. В исходном определении scale-list рекурсивная структура программы привлекает внимание к поэлементной обработке списка. Определение scale-list через map устраняет этот уровень деталей и подчеркивает, что умножение преобразует список элементов в список результатов. Разница между этими двумя определениями состоит не в том, что компьютер выполняет другой процесс (это не так), а в том, что мы думаем об этом процессе по-другому. В сущности, map помогает установить барьер абстракции, который отделяет реализацию процедур, преобразующих списки, от деталей того, как выбираются и комбинируются элементы списков. Подобно барьерам на рисунке 2.1, эта абстракция позволяет нам свободно изменять низкоуровневые детали того, как реализованы списки, сохраняя концептуальную схему с операциями, переводящими одни последовательностив в другие. В разделе 2.2.3 такое использование последовательностей как способ организации программ рассматривается более подробно.

Обращаем внимание на выделенный фрагмент. vector.Begin() и vector.End() — это детали реализации контейнера, которые совершенно неважны в данном контексте, и так понятно, что раз надо что-то перебирать, то соответствующие методы у коллекции быть должны.

annoynimous ★★★★★
()
Ответ на: комментарий от Obey-Kun

лучше:

register size_t len = dimensions.size();
for (register size_t i = 0; i < len; i++) {
    volume *= dimensions[i];
}

Ну или:

for (vector<double>::const_iterator i = dimensions.begin(); i != dimensions.end(); i++) {
    volume *= *i;
}

rymis ★★
()
Ответ на: комментарий от jtootf

А твой use case в духе абстрактного программирования должен решаться комбинированием filter и map(foreach): сначала мы их коллекции достаем элементы с заданными свойствами (например, определенного положения), а потом делаем с ними, что необходимо. Такая идиома работает не только с коллекциями-обобщениями массивов, но и, например, с бесконечными потоками.

annoynimous ★★★★★
()
Ответ на: комментарий от annoynimous

А твой use case в духе абстрактного программирования должен решаться комбинированием filter и map

это несколько, гм, разные вещи

сначала мы их коллекции достаем элементы с заданными свойствами

в случае использования итераторов мы ничего не достаём. мы просто определяем множество, с которым работаем, в терминах его границы

Такая идиома работает не только с коллекциями-обобщениями массивов, но и, например, с бесконечными потоками.

ну покажи как с помощью map/filter красиво и эффективно утроить (например) второй, третий, и четвёртый элемент списка

jtootf ★★★★★
()
Ответ на: комментарий от rymis
for (vector<double>::const_iterator i = dimensions.begin(); i != dimensions.end(); i++) { 
    volume *= *i; 
} 
volume = accumulate(dimensions.begin(), dimensions.end(), volume, multiplies<double>());
jtootf ★★★★★
()

ты пытаешься использовать map (for_each) вместо fold (accumulate). ещё и неверно пытаешься

jtootf ★★★★★
()

Гонишься за модой - юзай пайтон.
Хочешь сипэпэ - жуй простыни ошибок темплейтов.
Вот и вся правда.

tia
()
Ответ на: комментарий от Absurd

нефункционально. да, благодаря изменяемому состоянию на С++ можно реализовать свёртку посредством for_each - но зачем?

jtootf ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.