Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Для новичков > Как создать манипулятор и перегрузить оператор


Автор: neosapient 28.8.2014, 10:59
Здравствуйте.

Допустим есть класс summator. Он получает параметры через перегруженный оператор <<, а затем суммирует их.
Хочу сделать манипулятор calc, который бы производил расчет в момент его вызова. Помогите исправить ошибку.
Пример, что хотелось бы получить
   sum << 1 << 2 << "3" << calc;

Пример не рабочего кода
Код

#include <list>
#include <iostream>
#include <sstream>


class summator{
    std::list<int> vars;

public:
    summator& operator << (int o)
    {
        vars.push_back(o);
        return *this;
    }

    summator& operator << (char *o)
    {
        vars.push_back(atoi(o));
        return *this;
    }

    summator& calc (summator& o)
    {
        int sum = 0;
        while(!vars.empty()){
            sum += vars.front();
            vars.pop_front();
        }
        std::cout << "sum = " << sum;
        return *this;
    }
};

int main(int argc, char* argv[])
{
    summator sum;
    sum << 1 << 2 << "3";
    //sum << summator::calc; // обращение к манипулятору не работает
    sum.calc(sum); // по этому пока вызываю на прямую
    return 0;
}


Сообщение об ошибке, которое возникает при обращении к манипулятору sum << summator::calc; в строке 38
Цитата

1>c:\users\smbd\desktop\test\test.cpp(38) : error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'overloaded-function' (or there is no acceptable conversion)
1>        c:\users\smbd\desktop\test\test.cpp(14): could be 'summator &summator::operator <<(int)'
1>        c:\users\smbd\desktop\test\test.cpp(20): or       'summator &summator::operator <<(char *)'
1>        'summator::calc': function call missing argument list; use '&summator::calc' to create a pointer to member
1>        while trying to match the argument list '(summator)'

Как исправить?

Модератор: не используй тег CODE для цитирования сообщений об ошибках - портится форматирование форума

Автор: borisbn 28.8.2014, 13:20
В твоём классе не описан оператор <<, который бы получал на вход функцию. Д.б. как-то так

Код
summator& operator << ( summator & (summator::*f)( summator & ) ) {
    (this->*f)( *this );
    return *this;
}


И ещё. Вызов должен быть таким:
Код
    sum << 1 << 2 << "3" << & summator::calc;


Вот - http://ideone.com/aYThBO - подправленный вариант

Автор: neosapient 28.8.2014, 16:11
borisbn, спасибо за ответ.

Меня вот что смущает: когда я использую 
std::stringstream ss;
ss << "Hello, World!" << std::endl;

то для std::endl нет никаких добавочных символов, типа
ss << "Hello, World!" << & std::endl;

Как реализовать манипулятор на подобии стандартной библиотеки?

Автор: neosapient 28.8.2014, 23:54
Для статичных функций преобразование типов к указателю происходит автоматически.
http://ideone.com/phSsHX

Код

#include <stdlib.h>
#include <list>
#include <iostream>
#include <sstream>

class summator{

    std::list<int> vars;

public:
    summator& operator << (int o)
    {
        vars.push_back(o);
        return *this;
    }

    summator& operator << (const char *o)
    {
        vars.push_back(atoi(o));
        return *this;
    }

     
    summator& operator << ( summator & (*f)( summator & ) )
    {
        (*f)( *this );
        return *this;
    }

    static summator& calc (summator& o)
    {
        int sum = 0;
        while(!o.vars.empty()){
            sum += o.vars.front();
            o.vars.pop_front();
        }
        std::cout << "sum = " << sum;
        return o;
    }
};




int main(int argc, char* argv[])
{
    summator sum;
    sum << 1 << 2 << "3" << summator::calc;
    return 0;
}

Автор: Alca 29.8.2014, 10:04
функторы?

Автор: neosapient 25.9.2014, 18:14
Цитата(Alca @  29.8.2014,  10:04 Найти цитируемый пост)
функторы? 

Приведите пример работы через функторы, чтобы сохранить семантику std::endl

Автор: tzirechnoy 26.9.2014, 08:42
Ну, как в C++ сделать так, чтобы это было Вам ужэ сказали -- так что просто совет.

Возьмите для таких вещей Haskell.

У него есть два большых плюса: первый -- что по факту там такого гораздо большэ, и подобные интеллектуальные упражнения на нём можно проводить очень долго. Вот, например, функцыя на 9 строк: http://www.haskell.org/ghc/docs/6.12.2/html/libraries/base-4.2.0.1/src/Data-List.html#permutations, из стандартной библиотеки -- дажэ после того, как чётко сгруппируешь все вызовы и все параметры -- на понимание работы можэт уйти довольно много времени, и лучшэ почитать литературу, чтобы понять, что это они сделали и зачем.

Второй плюс хаскелля -- что вся эта хрень никогда не попадёт в production, и ты сам через пол-года и твои коллеги не будут материться и спотыкаться выясняя, что ещё ты там наизвращал и как надо нестандартно понимать стандартные операторы в конкретно этот файле.

Автор: borisbn 26.9.2014, 08:50
Цитата(neosapient @  25.9.2014,  18:14 Найти цитируемый пост)
 чтобы сохранить семантику std::endl 

Тогда тебе нужно сделать ф-цию calc свободной (как и ф-ция endl). Как-то так
Код

#include <list>
#include <iostream>
#include <sstream>
class summator{
    std::list<int> vars;
public:
    summator& operator << (int o)
    {
        vars.push_back(o);
        return *this;
    }
    summator& operator << (const char *o)
    {
        vars.push_back(atoi(o));
        return *this;
    }
    summator& calc_internal()
    {
        int sum = 0;
        while(!vars.empty()){
            sum += vars.front();
            vars.pop_front();
        }
        std::cout << "sum = " << sum;
        return *this;
    }
    
    summator& operator << ( summator & (f)( summator & ) ) {
        return f( *this );
    }    
};

summator & calc( summator & o )
{
    return o.calc_internal();
}

int main(int argc, char* argv[])
{
    summator sum;
    sum << 1 << 2 << "3" << calc;
    return 0;
}


http://ideone.com/aYThBO

Автор: baldina 26.9.2014, 11:49
neosapient, 
Код

class summator {
  vector<int> data;
  public:
    summator& operator<<(int rhs) { 
      data.push_back(rhs); 
      return *this;
    }
    int get () const {
       return accumulate (data.begin(), data.end(), 0);
    }
};

int main() {
    summator sum;
    sum << 1 << 2 << 3;
    cout << sum.get();
}

http://ideone.com/fork/9dK9vw
или 

Код

class sequence {
  vector<int> data;

  public:
    sequence& operator<<(int rhs) { 
      data.push_back(rhs);
      return *this;
    }
    sequence& operator<<(function<int(int,int)> binary_op) {
      if (data.size() > 1) {
        int result = accumulate (data.begin()+1, data.end(), *data.begin(), binary_op);
        data.clear();
        data.push_back (result);
      }
      return *this;
    }
    sequence& operator<<(function<int(int)> unary_op) {
      transform(data.begin(), data.end(), data.begin(), unary_op);      
      return *this;
    }

    friend ostream& operator<<(ostream&,const sequence&);
};

ostream& operator<<(ostream& os,const sequence& seq) {
  copy (seq.data.begin(), seq.data.end(), ostream_iterator<int>(os," "));
  return os;
}


auto sum = plus<int>();
auto prod = multiplies<int>();
auto change_sign = [](int x)->int { return -x; };
int sqr (int x) { return x*x; }

int main() {
    sequence seq;
    seq << 1 << 2 << 3 << sum << 4 << 5 << prod << 2 << sqr << -42 << change_sign;
    cout << seq;
}

http://ideone.com/YnvBqL

Автор: NoviceF 29.9.2014, 09:55
Цитата(tzirechnoy @  26.9.2014,  09:42 Найти цитируемый пост)
как надо нестандартно понимать стандартные операторы в конкретно этот файле. 

Ну может в данном случае это и не очевидно, но сама по себе подобная техника интересна, например, для логгера. Я вот раньше подобное не встречал, хотя в своё время пытался найти инфу на тему.

Так что всем спасибо за инфу и примеры smile

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)