No more ugly functors
От: folk Россия  
Дата: 07.11.03 04:45
Оценка: 15 (1) :)
Навеяно словами WolfHound'a в ветке C++/CLI PDC presentation
Автор: alexkro
Дата: 01.11.03

Вот создал макрос для перебора всех элементов контейнера, стараясь как можно больше приблизиться к
приведенному там синтаксису.
В результате организация цикла выглядит примерно так: FOR_EACH(int& i, the_container)

Определение макроса:

namespace _foreach
{

class base {};

template <typename T>
struct wrapper : public base
{
  mutable T wrapped;
  wrapper(const T& t): wrapped(t) {}
};

template <typename T> 
wrapper<T> wrap(const T& t)
{ return t; }

template <typename T>
T& unwrap(const base& b, const T&)
{ return static_cast<const wrapper<T>&>(b).wrapped; }

} // end namespace foreach

#define FOR_EACH_(Decl, First, Last) \
if (false) {} else /*VC6 for-init-scope bug workaround*/ \
  for (const _foreach::base &_fe_cur = _foreach::wrap(First), &_fe_last = _foreach::wrap(Last); \
    _foreach::unwrap(_fe_cur, First) != _foreach::unwrap(_fe_last, Last); \
      ++_foreach::unwrap(_fe_cur, First)) \
        if (bool _fe_once = false) {} else \
          for (Decl = *_foreach::unwrap(_fe_cur, First); !_fe_once; _fe_once = true)    \
// end macro

#define FOR_EACH(Decl, Cont)    FOR_EACH_(Decl, (Cont).begin(), (Cont).end())


Использование:

#include <vector>
#include <set>
#include <string>
#include <iostream>

using namespace std;

int main(int argc, const char* argv[])
{
    std::set<std::string> str_set;
    str_set.insert("red");
    str_set.insert("green");
    str_set.insert("blue");
    FOR_EACH(const string& s, str_set) cout << s << endl;

    std::vector<short> short_vec;
    short_vec.push_back(-2);
    short_vec.push_back(-1);
    short_vec.push_back(0);
    FOR_EACH(short& i, short_vec) ++i;
    FOR_EACH(int i, short_vec)
    {
        if (i >= 0 && i < argc) cout << argv[i] << endl;
        else cout << i << endl;
    }
    return 0;
}


Вижу в этом решении следующие проблемы (не считая проблем идеологического характера):

1. break работает точно так же, как continue, а хотелось бы полного соответствия семантике цикла.

2. Постоянные ненужные вызовы container.begin() и container.end(), служащие только для определения того, к какому типу надо приводить базовую ссылку. Но проверка asm-листинга VC6 для этого примера показала что все эти вызовы выкидывются оптимизатором. Для VC7.1 даже проверять не стал.
Если бы имелся оператор typeof, то такой проблемы не возникло бы вообще.

3. Ну и конечно же неудобства при отладке такого макроса.

Несмотря на все это я уже второй день пользую FOR_EACH и FOR_EACH_ и очень доволен.
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re: No more ugly functors
От: Юнусов Булат Россия  
Дата: 07.11.03 04:55
Оценка:
Здравствуйте, folk, Вы писали:

Чем функторы то так не нравятся, рульно же когда цикл в одном месте а алгоритм в другом — нафига обртно все в кучу упихивать то?
Re[2]: No more ugly functors
От: Шахтер Интернет  
Дата: 07.11.03 06:52
Оценка: :))) :))) :)
Здравствуйте, Юнусов Булат, Вы писали:

ЮБ>Здравствуйте, folk, Вы писали:


ЮБ>Чем функторы то так не нравятся, рульно же когда цикл в одном месте а алгоритм в другом — нафига обртно все в кучу упихивать то?


Доказывать с пеной у рта не буду, но по-моему не рульно. Потому что расщепляет некую целостность на два фрагмента, далеко расположенных по тексту друг от друга.

Далее. Есть такой принцип : make simple things simple. Или по-русски: не надо для убиения одного комара кидать ядрёную бонбу.

Фактически, единственный профит от for_each, например, то что кишки упрятаны. Типа меньше ошибок и своего рода инкапсуляция получается.
Ну так придумайте инкапсуляцию для операторов как свойство языка. Это было бы, по-моему, куда более продуктивно. Вместо того, чтобы вкладывать колоссальные усилия в реализации на шаблонах. Там нужны усилия и здесь, только в одном случае результатом будет заточка инструмента под решение задач, а во втором -- притягивние задач за уши к инструменту. Т.е. в одном случае продуктивная взаимная любовь, а в другом -- изнасилование.

/* main.cpp */ 

#include <iostream>

using namespace std;

#define dimof(v) ((sizeof v)/(sizeof *v))

/* main() */ 

int main()
 {
  int v[10];
  
  v[0]=v[1]=1;
  
  for(int *p=v+2,*lim=v+dimof(v); p<lim ;p++) *p=p[-1]+p[-2];
  
  for(int *p=v,*lim=v+dimof(v); p<lim ;p++) cout << *p << endl ;
 
  return 0;
 }


Поясню немного. Что есть выделенное жирным шрифтом. Оператор цикла, да? После него стоит тело, к которму он применяется.
Фактичкски, здесь стоит inline определение некоторой сущности. Что хочется. Это определение сделать outline. Скрыть детальки, оставив наруже только интерфейс -- входной и операторный. Тогда циклирование сведется к двум шагам: построение этого оператора и применение его к, между прочим, тоже некотрой inline определённой сущности. Ага? Алгоритм же for_each не решает задачи, он просто убирает с глаз долой сам цикл и ничего больше. Не, он ещё создаёт сложности в связывании с телом.

Создаём объект F. Засовываем его через аргумент. Зачем-то. Хотя всё что нужно для дела -- рабочая головка().

Fun F;

for_each(...,F);

/* for(...) F(*p); */


А если не копируется? Значит, бежим за вазелином.

template <class Fun>
struct Adapter
 {
  Fun *ptr;

  Adapter(Fun &object) : ptr(&object) {}

  template <class T>
  void operator (T x) { (*ptr)(x); } 
 };


Тут главное -- марку вазелина не перепутать.

template <class Fun>
struct AdapterRef
 {
  Fun *ptr;

  AdapterRef(Fun &object) : ptr(&object) {}

  template <class T>
  void operator (T &x) { (*ptr)(x); } 
 };


А то или опять не войдет, или войдет с лишним напрягом. Или даже с незаметным побочным эффектом. Треснет что-нибудь где-нибудь.

Можно ещё хирургию сделать. Опытные хирурги из фирмы boost впаяют такой счетчик ссылок вовнутрь что сразу закопируется. Через все аргументы.
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re: Just one ugly macro...
От: alexkro  
Дата: 07.11.03 07:29
Оценка:
Здравствуйте, folk, Вы писали:

F>Навеяно словами WolfHound'a в ветке C++/CLI PDC presentation
Автор: alexkro
Дата: 01.11.03

F>Вот создал макрос для перебора всех элементов контейнера, стараясь как можно больше приблизиться к
F>приведенному там синтаксису.
F>В результате организация цикла выглядит примерно так: FOR_EACH(int& i, the_container)

F>Определение макроса:


...

А как тебе версия Niebler'а? (ftp://ftp.cuj.com/pub/2003/cujnov2003.zip).
Re: No more ugly functors
От: astel  
Дата: 07.11.03 08:19
Оценка:
Здравствуйте, folk, Вы писали:

F>Навеяно словами WolfHound'a в ветке C++/CLI PDC presentation
Автор: alexkro
Дата: 01.11.03

F>Вот создал макрос для перебора всех элементов контейнера, стараясь как можно больше приблизиться к
F>приведенному там синтаксису.
F>В результате организация цикла выглядит примерно так: FOR_EACH(int& i, the_container)

F>Определение макроса:


F>
F>namespace _foreach
F>{

F>class base {};

F>template <typename T>
F>struct wrapper : public base
F>{
F>  mutable T wrapped;
F>  wrapper(const T& t): wrapped(t) {}
F>};

F>template <typename T> 
F>wrapper<T> wrap(const T& t)
F>{ return t; }

F>template <typename T>
F>T& unwrap(const base& b, const T&)
F>{ return static_cast<const wrapper<T>&>(b).wrapped; }

F>} // end namespace foreach

F>#define FOR_EACH_(Decl, First, Last) \
F>if (false) {} else /*VC6 for-init-scope bug workaround*/ \
F>  for (const _foreach::base &_fe_cur = _foreach::wrap(First), &_fe_last = _foreach::wrap(Last); \
F>    _foreach::unwrap(_fe_cur, First) != _foreach::unwrap(_fe_last, Last); \
F>      ++_foreach::unwrap(_fe_cur, First)) \
F>        if (bool _fe_once = false) {} else \
F>          for (Decl = *_foreach::unwrap(_fe_cur, First); !_fe_once; _fe_once = true)    \
F>// end macro

F>#define FOR_EACH(Decl, Cont)    FOR_EACH_(Decl, (Cont).begin(), (Cont).end())
F>


Классная штука !
Не мог бы ты пояснить как работает макрос FOR_EACH_ ? А то не совсем понятно применение врапперов и вложенных циклов.
Re[3]: No more ugly functors
От: Аноним  
Дата: 07.11.03 09:31
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш>Фактически, единственный профит от for_each, например, то что кишки упрятаны.


Есть второй: оптимизация вычисления конечного итератора без явного введения дополнительной переменной.
Re[3]: No more ugly functors
От: Юнусов Булат Россия  
Дата: 07.11.03 10:16
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш>Доказывать с пеной у рта не буду, но по-моему не рульно. Потому что расщепляет некую целостность на два фрагмента, далеко расположенных по тексту друг от друга.


А нужна она эта целостность? Что лучше отлаживать сам-по-себе одинокий функтор или цикл посреди остального кода?

Ш>Далее. Есть такой принцип : make simple things simple. Или по-русски: не надо для убиения одного комара кидать ядрёную бонбу.


С каких это пор тривиальные вещи стали бомбой? Давай без эмоций и эротических фантазий — они тут неуместы.
Ты во что форич выливается в исходниках видел?

Ш>Фактически, единственный профит от for_each, например, то что кишки упрятаны. Типа меньше ошибок и своего рода инкапсуляция получается.


Если чел. видит for_each, transform, copy, find_if и.т.п то понять чужой код ему гораздо проще чем лазить по циклам.
Впрочем Мейерс лучше сказал http://www.cuj.com/documents/s=8191/cuj0110smeyers/

Кроме того алгоритмы меж собой хорошо сочетаются, вкладываются итп.

Твою задачу тоже можно в функтор посадить, поставить еще бы проверок на все что можно и дальше пользоватся.
struct miner {
    int * data_;
    size_t i_;
    miner(int * data) : data_(data), i_(0) { data_[0] = data_[1] = 1; } 
    int operator()(int) {
        if (i_ < 2)
            return ++i_, 1;
        return data_[i_-1] + data_[i_++ -2];
    }
};

int main(int argc, char* argv[])
{
    int d[10] = {0};
    std::copy(d, std::transform(d, d+10, d, miner(d)), std::ostream_iterator<int>(std::cout, "\n")); // имхо так красивше

    return 0;
}
Re[2]: Just one ugly macro...
От: WolfHound  
Дата: 07.11.03 16:11
Оценка:
Здравствуйте, alexkro, Вы писали:

A>А как тебе версия Niebler'а? (ftp://ftp.cuj.com/pub/2003/cujnov2003.zip).

И чем он лучше кроме того что там написано больше?
... << RSDN@Home 1.1 beta 2 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re: No more ugly functors
От: WolfHound  
Дата: 07.11.03 16:11
Оценка: 28 (3)
Здравствуйте, folk, Вы писали:

F>Навеяно словами WolfHound'a в ветке C++/CLI PDC presentation
Автор: alexkro
Дата: 01.11.03

F>Вот создал макрос для перебора всех элементов контейнера, стараясь как можно больше приблизиться к
F>приведенному там синтаксису.
F>В результате организация цикла выглядит примерно так: FOR_EACH(int& i, the_container)
хъ
Красота (ну почти см ниже)

F>Вижу в этом решении следующие проблемы (не считая проблем идеологического характера):

Нет ни каких проблем есть фанатизм.

F>1. break работает точно так же, как continue, а хотелось бы полного соответствия семантике цикла.

fixed
#include "stdafx.h"
namespace foreach_detail
{
    struct wrapper_holder{};

    template <typename T>
    struct wrapper
        :wrapper_holder
    {
        mutable T wrapped;
        wrapper(const T& t)
            :wrapped(t) 
        {}
    };

    template <typename T> 
    wrapper<T> wrap(const T& t)
    { 
        return t; 
    }

    template <typename T>
    T& unwrap(const wrapper_holder& b)
    { 
        return static_cast<const wrapper<T>&>(b).wrapped; 
    }

    template <typename T>
    T& unwrap(const wrapper_holder& b, const T&)
    { 
        return unwrap<T>(b); 
    }

    template <typename T>
    bool is_wrapped_equal(const wrapper_holder& lhs, const wrapper_holder& rhs, const T&)
    { 
        return unwrap<T>(lhs)==unwrap<T>(rhs);
    }
}

#define foreach_(Decl, First, Last)\
if(bool _fe_break = false){}else \
    for(const foreach_detail::wrapper_holder\
             &_fe_cur=foreach_detail::wrap(First)\
            ,&_fe_end=foreach_detail::wrap(Last)\
        ;!foreach_detail::is_wrapped_equal(_fe_cur, _fe_end, Last)&&!_fe_break\
        ;++foreach_detail::unwrap(_fe_cur, Last)\
        )\
        if(!(_fe_break=true)){}else\
        for(Decl=*foreach_detail::unwrap(_fe_cur, Last);_fe_break;_fe_break=false)\
// end macro

#define foreach(Decl, Cont)    foreach_(Decl, (Cont).begin(), (Cont).end())

F>2. Постоянные ненужные вызовы container.begin() и container.end(), служащие только для определения того, к какому типу надо приводить базовую ссылку. Но проверка asm-листинга VC6 для этого примера показала что все эти вызовы выкидывются оптимизатором. Для VC7.1 даже проверять не стал.
В асм иногода заглядывать надо
В первом варианте в место
        if(!(_fe_break=true)){}else\
        for(Decl=*foreach_detail::unwrap(_fe_cur, Last);_fe_break;_fe_break=false)\

было
        for(Decl=*foreach_detail::unwrap(_fe_cur, Last);_fe_break=!_fe_break;)\

тест
    std::vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    v.push_back(5);

    int s=1;
    foreach(int& i, v)
    {
        s*=i;
    }

и получалось
    cmp    edi, esi
    push    ebp
    mov    ecx, 1
    mov    ebp, edi
    je    SHORT $L10897
    push    ebx
$L20823:
    mov    edx, DWORD PTR [ebp]
    mov    al, 1
$L10901:

; 68   :     {
; 69   :         s*=i;

    mov    ebx, edx
    imul    ecx, ebx
    test    al, al
    sete    al
    test    al, al
    jne    SHORT $L10901
    add    ebp, 4
    cmp    ebp, esi
    jne    SHORT $L20823
    pop    ebx
$L10897:

Интересно он сам понял что написал

Хотя может же если мозги не пудрить
    cmp    edi, esi
    mov    eax, 1
    mov    ecx, edi
    je    SHORT $L10897
$L20663:

; 69   :     {
; 70   :         s*=i;

    mov    edx, DWORD PTR [ecx]
    add    ecx, 4
    imul    eax, edx
    cmp    ecx, esi
    jne    SHORT $L20663
$L10897:

Это практически 1 в 1 с
    s=1;
    for(std::vector<int>::iterator i=v.begin(), e=v.end();i!=e;++i)
    {
        s*=*i;
    }

(компилятор другие регистры использовал)
    cmp    edi, esi
    mov    ecx, 1
    mov    eax, edi
    je    SHORT $L10964
$L20765:

; 76   :     {
; 77   :         s*=*i;

    mov    edx, DWORD PTR [eax]
    add    eax, 4
    imul    ecx, edx
    cmp    eax, esi
    jne    SHORT $L20765
$L10964:

Но при использовании break оптимизатор не смог избавится от оверхеда
    int s=1;
    foreach(int& i, v)
    {
        if(i==3)break;
        s*=i;
    }

    s=1;
    for(std::vector<int>::iterator i=v.begin(), e=v.end();i!=e;++i)
    {
        if(*i==3)break;
        s*=*i;
    }

; 67   :     int s=1;
; 68   :     foreach(int& i, v)

    xor    cl, cl
    cmp    edi, esi
    mov    edx, edi
    je    SHORT $L10897
    npad    5
$L20665:
    cmp    cl, bl
    jne    SHORT $L10897

; 69   :     {
; 70   :         if(i==3)break;

    mov    eax, DWORD PTR [edx]
    cmp    eax, 3
    mov    cl, 1
    je    SHORT $L10896

; 71   :         s*=i;

    imul    eax, ebp
    mov    ebp, eax
    xor    cl, cl
$L10896:
    add    edx, 4
    cmp    edx, esi
    jne    SHORT $L20665
$L10897:

; 74   : 
; 75   :     s=1;
; 76   :     for(std::vector<int>::iterator i=v.begin(), e=v.end();i!=e;++i)

    cmp    edi, esi
    mov    edx, 1
    mov    ecx, edi
    je    SHORT $L20822
    npad    1
$L20767:

; 77   :     {
; 78   :         if(*i==3)break;

    mov    eax, DWORD PTR [ecx]
    cmp    eax, 3
    je    SHORT $L20822

; 79   :         s*=*i;

    imul    eax, edx
    add    ecx, 4
    cmp    ecx, esi
    mov    edx, eax
    jne    SHORT $L20767
$L20822:

Но с continue оверхеда не возникло.

F>Если бы имелся оператор typeof, то такой проблемы не возникло бы вообще.

Ох и не говори... сколько бы он сразу проблем решил...
F>3. Ну и конечно же неудобства при отладке такого макроса.
А зачем его отлаживать? Один раз написал и все

F>Несмотря на все это я уже второй день пользую FOR_EACH и FOR_EACH_ и очень доволен.



Итого:
1)Оптимизатор в VC++7.1 работает на отлично с ооочень маленьким минусом.
2)Учитывая что
а)Я уже и не помню когда мне был нужен break/continue
б)А цикл с такой смешной нагрузкой я использовал еще раньше...
Утверждаю к использованию в своих проектах.
... << RSDN@Home 1.1 beta 2 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[2]: No more ugly functors
От: WolfHound  
Дата: 07.11.03 17:58
Оценка:
Здравствуйте, WolfHound, Вы писали:

А если еще добавить
//По умолчанию считаем контейнеры STL совместимыми
template<class container_t>
struct container_traits
{
    typedef typename container_t::iterator iterator;
    typedef typename container_t::const_iterator const_iterator;
};

template<class container_t>
typename container_traits<container_t>::iterator
    container_begin(container_t& container)
{
    return container.begin();
}
template<class container_t>
typename container_traits<container_t>::iterator
    container_end(container_t& container)
{
    return container.end();
}

template<class container_t>
typename container_traits<container_t>::const_iterator
    container_begin(const container_t& container)
{
    return container.begin();
}
template<class container_t>
typename container_traits<container_t>::const_iterator
    container_end(const container_t& container)
{
    return container.end();
}
//Реализация для массивов
template<class value_t, size_t size_n>
struct container_traits<value_t[size_n]>
{
    typedef typename value_t* iterator;
    typedef typename const value_t* const_iterator;
};

template<class value_t, size_t size_n>
typename container_traits<value_t[size_n]>::iterator
    container_begin(value_t(&container)[size_n])
{
    return container;
}
template<class value_t, size_t size_n>
typename container_traits<value_t[size_n]>::iterator
    container_end(value_t(&container)[size_n])
{
    return container+size_n;
}

template<class value_t, size_t size_n>
typename container_traits<value_t[size_n]>::const_iterator
    container_begin(const value_t(&container)[size_n])
{
    return container;
}
template<class value_t, size_t size_n>
typename container_traits<value_t[size_n]>::const_iterator
    container_end(const value_t(&container)[size_n])
{
    return container+size_n;
}

и изменить
#define foreach(Decl, Cont)    foreach_(Decl, (Cont).begin(), (Cont).end())
на
#define foreach(Decl, Cont)    foreach_(Decl, container_begin(Cont), container_end(Cont))

То можно будет писать так
int _tmain(int argc, _TCHAR* argv[])
{
    std::vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    v.push_back(5);

    foreach(int& i, v)
    {
        std::cout<<i<<" ";
    }
    std::cout<<"\n\n";
    char str[]="asd";
    foreach(char c, str)
    {
        std::cout<<c;
    }
    std::cout<<"\n\n";
    std::string strings[]={"234", "asd", "qew", "sfd", "fdsg"};
    foreach(std::string str, strings)
    {
        foreach(char c, str)
        {
            std::cout<<c;
        }
        std::cout<<"\n";
    }
    std::cout<<"\n";
    return 0;
}


ЗЫ ИМХО container_traits (ну если еще доработать) самое место в STL. Что скажите?
... << RSDN@Home 1.1 beta 2 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[3]: Just one ugly macro...
От: alexkro  
Дата: 07.11.03 18:34
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Здравствуйте, alexkro, Вы писали:


A>>А как тебе версия Niebler'а? (ftp://ftp.cuj.com/pub/2003/cujnov2003.zip).

WH>И чем он лучше кроме того что там написано больше?

Для массивов работает, например. Да и, вообще, уважаемый человек написал.
Re[4]: Just one ugly macro...
От: WolfHound  
Дата: 07.11.03 20:06
Оценка:
Здравствуйте, alexkro, Вы писали:

A>>>А как тебе версия Niebler'а? (ftp://ftp.cuj.com/pub/2003/cujnov2003.zip).

WH>>И чем он лучше кроме того что там написано больше?
A>Для массивов работает, например.
Ну мой тоже.
А еще чем?
A>Да и, вообще, уважаемый человек написал.
Не аргумент.

А вот чем его вариант хуже я могу сказать... Слабо скормить два итератора?
... << RSDN@Home 1.1 beta 2 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[5]: Just one ugly macro...
От: alexkro  
Дата: 08.11.03 02:11
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Здравствуйте, alexkro, Вы писали:


A>>>>А как тебе версия Niebler'а? (ftp://ftp.cuj.com/pub/2003/cujnov2003.zip).

WH>>>И чем он лучше кроме того что там написано больше?
A>>Для массивов работает, например.
WH>Ну мой тоже.
WH>А еще чем?

Если тебе интересно, посмотри здесь: http://aspn.activestate.com/ASPN/Mail/Message/boost/1834496

A>>Да и, вообще, уважаемый человек написал.

WH>Не аргумент.

Для меня аргумент. Я видел больше его кода, чем твоего.

WH>А вот чем его вариант хуже я могу сказать... Слабо скормить два итератора?


using boost::for_each::in_range;
BOOST_FOREACH( int i, in_range( iter1, iter2 ) )
{
...
}
Re[2]: No more ugly functors
От: folk Россия  
Дата: 08.11.03 04:05
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>fixed

[]

Ok, все беру, и твое решение с break, и стилевые изменения. Только имена макросов все же оставлю заглавными буквами.
Правда я еще не смотрел ссылки от alexkro, сейчас этим и займусь.

А специализации для массивов я не стал создавать потому что у меня на работе используется VC6, соответственно код должен быть VC6-совместимым. Так что для меня лямбда как правило недоступна и утверждение "No more ugly functors (and explicit cycles)" очень актуально.
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[4]: No more ugly functors
От: Шахтер Интернет  
Дата: 08.11.03 04:23
Оценка: -3 :)
Здравствуйте, Юнусов Булат, Вы писали:

ЮБ>Впрочем Мейерс лучше сказал http://www.cuj.com/documents/s=8191/cuj0110smeyers/


ЮБ>Кроме того алгоритмы меж собой хорошо сочетаются, вкладываются итп.


ЮБ>Твою задачу тоже можно в функтор посадить, поставить еще бы проверок на все что можно и дальше пользоватся.

ЮБ>
ЮБ>struct miner {
ЮБ>    int * data_;
ЮБ>    size_t i_;
ЮБ>    miner(int * data) : data_(data), i_(0) { data_[0] = data_[1] = 1; } 
ЮБ>    int operator()(int) {
ЮБ>        if (i_ < 2)
ЮБ>            return ++i_, 1;
ЮБ>        return data_[i_-1] + data_[i_++ -2];
ЮБ>    }
ЮБ>};

ЮБ>int main(int argc, char* argv[])
ЮБ>{
ЮБ>    int d[10] = {0};
ЮБ>    std::copy(d, std::transform(d, d+10, d, miner(d)), std::ostream_iterator<int>(std::cout, "\n")); // имхо так красивше

ЮБ>    return 0;
ЮБ>}
ЮБ>


Я попрошу не обижаться, но не считаю возможным с вами дискутировать. А то мне придётся нарушить правила форума. Я надеюсь, что вы сами прочтёте свой код ещё раз и поймёте, что не правы.
Что касается господина Мейерса, то статью эту я читал. Мне она не понравилась. Автор явно не профессионал в программировании. Я так понимаю, он алгоритмист.
Смысл этой статьи -- в промоушене своих услуг. Такие вещи надо понимать, это Запад, всё-таки.

P.S.
Знаете, как отличить хорошего программиста от посредственного? По способности не делать мелких ляпов.
Так, профессиональный пианист не ошибается в гаммах, например.
И даю совет напоследок. Если постите код, даже иллюстративный, постарайтесь написать его чисто и аккуратно (и, естественно, правильно).
Не стоит ходить в оперу в заплатанных джинсах -- это неприлично.
... << RSDN@Home 1.1 beta 2 >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[2]: No more ugly functors
От: folk Россия  
Дата: 08.11.03 07:59
Оценка:
Здравствуйте, astel, Вы писали:

[]

A>Классная штука !

A>Не мог бы ты пояснить как работает макрос FOR_EACH_ ? А то не совсем понятно применение врапперов и вложенных циклов.

Сначала про врапперы.
Мы не хотим явно передавать тип контейнера в одном из аргументов макроса, так никакого попса не будет. В то же время для организации цикла нам нужно объявить два итератора — текущий и маркер окончания цикла.
Т.е. проблема в том что без оператора typeof мы никак не можем узнать какой тип итераторов указывать в объявлении.
Решение такое — с помощью функции wrap создаем 2 временных значения — обертки над итераторами и определяем 2 ссылки на базовый класс оберток (их тип известен). Эти обертки будут жить пока живут эти ссылки (thanx 2 jazzer).
Каждый раз когда нам нужно обратиться к итератору мы кастим ссылку на базу к ссыкле на обертку, а от обертки получаем итератор.

Про вложенные циклы.
Первый цикл нужен собственно для организации итерирования по контейнеру.
Второй цикл возвращает управление первому после одной итерации. Он служит только для объявления временного объекта и присвоения ему значения на которое указывает итератор.
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[6]: Just one ugly macro...
От: folk Россия  
Дата: 08.11.03 09:04
Оценка:
Здравствуйте, alexkro, Вы писали:

A>Здравствуйте, WolfHound, Вы писали:


WH>>Здравствуйте, alexkro, Вы писали:


A>>>>>А как тебе версия Niebler'а? (ftp://ftp.cuj.com/pub/2003/cujnov2003.zip).

WH>>>>И чем он лучше кроме того что там написано больше?
A>>>Для массивов работает, например.
WH>>Ну мой тоже.
WH>>А еще чем?

A>Если тебе интересно, посмотри здесь: http://aspn.activestate.com/ASPN/Mail/Message/boost/1834496


A>>>Да и, вообще, уважаемый человек написал.

WH>>Не аргумент.

A>Для меня аргумент. Я видел больше его кода, чем твоего.


WH>>А вот чем его вариант хуже я могу сказать... Слабо скормить два итератора?


A>using boost::for_each::in_range;

A>BOOST_FOREACH( int i, in_range( iter1, iter2 ) )
A>{
A> ...
A>}

Более поздний вариант на http://groups.yahoo.com/group/boost/files/BOOST_FOREACH/
уже не такое оружие массового поражения как вариант из CUJ, но конечно и далеко не такой маленький и простецкий как мой.

Если бы он вошел в поставку boost, то вполне возможно стал бы им пользоваться. Но, насколько я понял, этого не будет, несмотря на некоторые положительные отзывы, такое решение не приглянулось ценителям камерного искусства
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[5]: No more ugly functors
От: Юнусов Булат Россия  
Дата: 08.11.03 11:19
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш>Я попрошу не обижаться, но не считаю возможным с вами дискутировать. А то мне придётся нарушить правила форума. Я надеюсь, что вы сами прочтёте свой код ещё раз и поймёте, что не правы.


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

Ш>Что касается господина Мейерса, то статью эту я читал. Мне она не понравилась. Автор явно не профессионал в программировании. Я так понимаю, он алгоритмист.

Ш>Смысл этой статьи -- в промоушене своих услуг. Такие вещи надо понимать, это Запад, всё-таки.

Что надо понять? Что Мейерс как бы сказать помягче — популист? Использование stl — это низкопоклонство перез западом? STL Степанов изобрел вообще-то — тоже ради промоушена?
Впрочем, оставим Мейерса, ему не жарко ни холодно от ваших оценок.

Ш>P.S.

Ш>Знаете, как отличить хорошего программиста от посредственного? По способности не делать мелких ляпов.
Ш>Так, профессиональный пианист не ошибается в гаммах, например.
Ш>И даю совет напоследок. Если постите код, даже иллюстративный, постарайтесь написать его чисто и аккуратно (и, естественно, правильно).
Ш>Не стоит ходить в оперу в заплатанных джинсах -- это неприлично.

Я не Мейерс, но повертье, меня это тоже не задевает.

gcc3.3, vc6.0 sp5, vc7.1

ваш код выводит
1
1
2
3
5
8
13
21
34
55


мой вариант
1
1
2
3
5
8
13
21
34
55
Re[5]: От модератора форума C/C++
От: Павел Кузнецов  
Дата: 08.11.03 13:05
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш> Я попрошу не обижаться, но не считаю возможным с вами дискутировать.

Ш> А то мне придётся нарушить правила форума. Я надеюсь, что вы сами
Ш> прочтёте свой код ещё раз и поймёте, что не правы. <...>
Ш> P.S.
Ш> Знаете, как отличить хорошего программиста от посредственного? По
Ш> способности не делать мелких ляпов. Так, профессиональный пианист не
Ш> ошибается в гаммах, например. И даю совет напоследок. Если постите код,
Ш> даже иллюстративный, постарайтесь написать его чисто и аккуратно
Ш> (и, естественно, правильно). Не стоит ходить в оперу в заплатанных
Ш> джинсах -- это неприлично.

Обязательные правила форумов РСДН
http://www.rsdn.ru/rules.htm#IDAQT52B
Не допускается проявление грубого или неуважительного отношения к другим
участникам форума. Оскорблять и обзывать собеседника, ставить под сомнение
его профессиональную квалификацию, придираться к его нику, указывать
на орфографические и синтаксические ошибки и т. д. запрещается.


Настоятельно рекомендую воздерживаться от публикации сообщений, написанных
в таком снисходительно-высокомерном тоне, только на основании того, что ваш
оппонент склонен использовать другие технологии или пишет в стиле, отличном
от того, к которому вы привыкли.

P.S. На всякий случай, добавлю, что отвечать на данное сообщение в форуме
также не следует. Вопросы, пожелания и замечания относительно модерирования
этого и других форумов rsdn.ru — в .
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[6]: No more ugly functors
От: Аноним  
Дата: 08.11.03 13:42
Оценка:
Здравствуйте, Юнусов Булат, Вы писали:

ЮБ> но было бы сначала неплохо узнать где я неправ,


Булат, Вы промахнулись в этой строчке:
ЮБ>        return data_[i_-1] + data_[i_++ -2];
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.