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];
Re[3]: No more ugly functors
От: MaximE Великобритания  
Дата: 08.11.03 17:01
Оценка:
WolfHound wrote:

W> ЗЫ ИМХО container_traits (ну если еще доработать) самое место в STL. Что скажите?


[boost] review request: container_traits
http://groups.yahoo.com/group/boost/files/container_traits/

и еще ацтой по теме: [boost] any interesting in a foreach looping construct?
Posted via RSDN NNTP Server 1.8 beta
Re[7]: No more ugly functors
От: Юнусов Булат Россия  
Дата: 08.11.03 19:12
Оценка: -2
Здравствуйте, Аноним, Вы писали:

А>Булат, Вы промахнулись в этой строчке:

А>
ЮБ>>        return data_[i_-1] + data_[i_++ -2];
А>



Неа, это же постфиксный инкремент, так что этот код эквивалентен
        int rc = data_[i_-1] + data_[i_-2];
        ++i_;
        return rc;
Re[8]: No more ugly functors
От: GarryIV  
Дата: 08.11.03 21:44
Оценка:
Здравствуйте, Юнусов Булат, Вы писали:

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


А>>Булат, Вы промахнулись в этой строчке:

А>>
ЮБ>>>        return data_[i_-1] + data_[i_++ -2];
А>>



ЮБ>Неа, это же постфиксный инкремент, так что этот код эквивалентен

ЮБ>
ЮБ>        int rc = data_[i_-1] + data_[i_-2];
ЮБ>        ++i_;
ЮБ>        return rc;
ЮБ>


А по моему нет. У тебя неопределенное поведение.
WBR, Igor Evgrafov
Re[3]: No more ugly functors
От: MaximE Великобритания  
Дата: 08.11.03 22:25
Оценка:
Здравствуйте, Шахтер, Вы писали:

[]

Ш>Ну так придумайте инкапсуляцию для операторов как свойство языка. Это было бы, по-моему, куда более продуктивно.


Все уже придумано: boost::lambda.

Слышал, что предлагают добавить лямбда-выражения в core language.
Крокодилы в клетке
От: Шахтер Интернет  
Дата: 08.11.03 23:03
Оценка:
Здравствуйте, Юнусов Булат, Вы писали:

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


А>>Булат, Вы промахнулись в этой строчке:

А>>
ЮБ>>>        return data_[i_-1] + data_[i_++ -2];
А>>



ЮБ>Неа, это же постфиксный инкремент, так что этот код эквивалентен

ЮБ>
ЮБ>        int rc = data_[i_-1] + data_[i_-2];
ЮБ>        ++i_;
ЮБ>        return rc;
ЮБ>


Очень неудобно вставлять (текст) из стандарта.

[Clause 5]
<skipped>

4 Except where noted, the order of evaluation of operands of individual operators and subexpressions of individual
expressions, and the order in which side effects take place, is unspecified.53) Between the previous
and next sequence point a scalar object shall have its stored value modified at most once by the evaluation
of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored.
The requirements of this paragraph shall be met for each allowable ordering of the subexpressions of a full
expression; otherwise the behavior is undefined. [Example:
i = v[i++]; // the behavior is unspecified
i = 7, i++, i++; // i becomes 9
i = ++i + 1; // the behavior is unspecified
i = i + 1; // the value of i is incremented
—end example]

Короче, обьясняю по-простому. Компилятор, разбирая выражение, строит дерево разбора. В дальнейшем, он должен выбрать некоторый порядок обхода этого дерева (усилить отношение частичного порядка до линейного). Вообще говоря, это можно сделать многими разными способами. Более того, здесь таится опасность комбинаторного взрыва, в том смысле, что число всех вариантов обхода растет экспоненциально. Так вот, если для двух таких вариантов вы получите функционально не эквивалентную последовательность операций вы проиграли. И даже не потому, что стандарт относит это к unspecified behavior, хрен с ним со стандартом. А потому, что результат вычисления такого выражения вы отдали на произвол компилятору. Т.е. вполне возможно, что где-нибудь после нескольких лет успешной работы (или даже после нескольки часов просто переключением опций компилятора) вы радикально измените свою программу и будете ооооочень долго искать, где же собака порылась. Можно было бы, конечно, договорится применять side-effectы в определённом месте, но это может войти в противоречие с аппаратурой, поскольку, например, некоторые процессоры прекрасно умеют делать авто-инкремент в регистрах. С анализом таких подвохов в compile-time тоже проблема, поскольку см. выше.
... << RSDN@Home 1.1 beta 2 >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[4]: No more ugly functors
От: Шахтер Интернет  
Дата: 08.11.03 23:43
Оценка:
Здравствуйте, MaximE, Вы писали:

ME>Здравствуйте, Шахтер, Вы писали:


ME>[]


Ш>>Ну так придумайте инкапсуляцию для операторов как свойство языка. Это было бы, по-моему, куда более продуктивно.


ME>Все уже придумано: boost::lambda.


ME>Слышал, что предлагают добавить лямбда-выражения в core language.


Вот если в core language, то это в coreне меняет дело.
... << RSDN@Home 1.1 beta 2 >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re: Крокодилы в клетке
От: Юнусов Булат Россия  
Дата: 09.11.03 00:16
Оценка:
Здравствуйте, Шахтер, Вы писали:

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


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


А>>>Булат, Вы промахнулись в этой строчке:

А>>>
ЮБ>>>>        return data_[i_-1] + data_[i_++ -2];
А>>>


Ок, значит я неправ. Акела промахнулся
Re: Крокодилы в клетке
От: Павел Кузнецов  
Дата: 10.11.03 08:01
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш> Between the previous and next sequence point a scalar object shall have

Ш> its stored value modified at most once by the evaluation of an expression.
Ш> Furthermore, the prior value shall be accessed only to determine
Ш> the value to be stored. The requirements of this paragraph shall be met for
Ш> each allowable ordering of the subexpressions of a full expression;
Ш> otherwise the behavior is undefined.
Ш> [Example:
Ш> i = v[i++]; // the behavior is unspecified
Ш> i = 7, i++, i++; // i becomes 9
Ш> i = ++i + 1; // the behavior is unspecified
Ш> i = i + 1; // the value of i is incremented
Ш> —end example]

Ш> стандарт относит это к unspecified behavior


Хуже: undefined.
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[2]: Крокодилы в клетке
От: Шахтер Интернет  
Дата: 11.11.03 04:04
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Здравствуйте, Шахтер, Вы писали:


Ш>> Between the previous and next sequence point a scalar object shall have

Ш>> its stored value modified at most once by the evaluation of an expression.
Ш>> Furthermore, the prior value shall be accessed only to determine
Ш>> the value to be stored. The requirements of this paragraph shall be met for
Ш>> each allowable ordering of the subexpressions of a full expression;
Ш>> otherwise the behavior is undefined.
Ш>> [Example:
Ш>> i = v[i++]; // the behavior is unspecified
Ш>> i = 7, i++, i++; // i becomes 9
Ш>> i = ++i + 1; // the behavior is unspecified
Ш>> i = i + 1; // the value of i is incremented
Ш>> —end example]

Ш>> стандарт относит это к unspecified behavior


ПК>Хуже: undefined.


В таком случае попрошу поподробнее. Почему в коментария написано unspecified (опечатка?). В чем разница между unspecified и undefined.
Только не надо отсылать к стандарту. У старенького дяди Шахтёра мозгА в этом стандарте не всё понимает.

И ещё. Раз у нас тут такие знатоки стандарта. В этом коде насколько оправдан вызов transform. Дело в том, что он читает данные из того же массива, в который пишет. Стандарт вроде не определяет, в каком точно порядке transform работает. Может он откладывает запись, например. Или вообще едет сверху вниз (это конечно маловероятно, но возможно). Или запускает несколько потоков на многопроцессорной системе.

Effects: Assigns through every iterator i in the range [ result, result + ( last1 first1))
a new corresponding value equal to op(*( first1 + (i result))
or
binary_op(*( first1 + (i result),
*( first2 + (i result))).

Requires: op and binary_op shall not have any side effects.

Что эта фраза означает?

ЮБ>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;
ЮБ>}
... << RSDN@Home 1.1 beta 2 >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re: Могу предложить альтернативу
От: lboss Россия  
Дата: 11.11.03 05:17
Оценка:
Здравствуйте, folk:


class VIterator
{
public:
    bool    m_break;
    VIterator()
        : m_break(false)
    {
    }
};

template <class TIterator>
class VIteratorImpl : public VIterator
{
public:
    TIterator    m_p;

    VIteratorImpl(TIterator p)
        : m_p(p)
    {
    }
};

template <class TIterator>
inline VIteratorImpl<TIterator>    vIteratorInit(TIterator pStart)
{
    return VIteratorImpl<TIterator>(pStart);
}

template <class TIterator>
inline bool    vIteratorCanContinue(VIterator & pIter, TIterator pEnd)
{
    return static_cast<VIteratorImpl<TIterator>& >(pIter).m_p != pEnd;
}

template <class TIterator>
inline void    vIteratorStep(VIterator & pIter, TIterator pEnd)
{
    ++static_cast<VIteratorImpl<TIterator>& >(pIter).m_p;
}

template <class TIterator>
inline typename TIterator::reference vIteratorGetValue(VIterator & pIter, TIterator pEnd)
{
    pIter.m_break = true;
    return *static_cast<VIteratorImpl<TIterator> & >(pIter).m_p;
}



#define FOREACH(varDef, collection)\
    for(\
        VIterator & pIterator = vIteratorInit(collection.begin());\
        !pIterator.m_break && vIteratorCanContinue(pIterator, collection.end());\
        vIteratorStep(pIterator, collection.end())\
        )\
        for(varDef = vIteratorGetValue(pIterator, collection.end()); pIterator.m_break; pIterator.m_break = false)


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

int _tmain(int argc, _TCHAR* argv[])
{
    std::vector<int> col;
    col.push_back(10);
    col.push_back(20);
    col.push_back(30);

    FOREACH(int val, col)
    {
        printf("%d\n", val);
    }

    return 0;
}
С уважением Вадим.
Re[2]: Могу предложить альтернативу
От: folk Россия  
Дата: 11.11.03 06:10
Оценка:
Здравствуйте, lboss, Вы писали:

L>Здравствуйте, folk:



L>
L>class VIterator
L>{
L>public:
L>    bool    m_break;
L>    VIterator()
L>        : m_break(false)
L>    {
L>    }
L>};

L>template <class TIterator>
L>class VIteratorImpl : public VIterator
L>{
L>public:
L>    TIterator    m_p;

L>    VIteratorImpl(TIterator p)
L>        : m_p(p)
L>    {
L>    }
L>};

L>template <class TIterator>
L>inline VIteratorImpl<TIterator>    vIteratorInit(TIterator pStart)
L>{
L>    return VIteratorImpl<TIterator>(pStart);
L>}

L>template <class TIterator>
L>inline bool    vIteratorCanContinue(VIterator & pIter, TIterator pEnd)
L>{
L>    return static_cast<VIteratorImpl<TIterator>& >(pIter).m_p != pEnd;
L>}

L>template <class TIterator>
L>inline void    vIteratorStep(VIterator & pIter, TIterator pEnd)
L>{
L>    ++static_cast<VIteratorImpl<TIterator>& >(pIter).m_p;
L>}

L>template <class TIterator>
L>inline typename TIterator::reference vIteratorGetValue(VIterator & pIter, TIterator pEnd)
L>{
L>    pIter.m_break = true;
L>    return *static_cast<VIteratorImpl<TIterator> & >(pIter).m_p;
L>}



L>#define FOREACH(varDef, collection)\
L>    for(\
L>        VIterator & pIterator = vIteratorInit(collection.begin());\
L>        !pIterator.m_break && vIteratorCanContinue(pIterator, collection.end());\
L>        vIteratorStep(pIterator, collection.end())\
L>        )\
L>        for(varDef = vIteratorGetValue(pIterator, collection.end()); pIterator.m_break; pIterator.m_break = false)
L>


( Напомню свою сигнатуру: #define FOR_EACH_(Decl, First, Last) )

Я тоже думал над подобным вариантом. Но на всякий случай решил не _использовать_ результат аргумента Last на каждой итерации. Это мне показалось более безопасным. Также я допускал что это облегчит жизнь оптимайзеру.

Опосля пришла мысль что лучше кастить к First, чем к Last, т.к. у тех реализаций контейнеров, что я видел, метод begin() устроен либо проще чем end(), либо они примерно одинаковы.
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[3]: Могу предложить альтернативу
От: lboss Россия  
Дата: 11.11.03 06:25
Оценка:
Здравствуйте, folk, Вы писали:


F>Я тоже думал над подобным вариантом. Но на всякий случай решил не _использовать_ результат аргумента Last на каждой итерации. Это мне показалось более безопасным. Также я допускал что это облегчит жизнь оптимайзеру.


F>Опосля пришла мысль что лучше кастить к First, чем к Last, т.к. у тех реализаций контейнеров, что я видел, метод begin() устроен либо проще чем end(), либо они примерно одинаковы.


Ну я наоборот считаю end() более простой операцией — так как это же fake'овый объект как правило и его проще построить.


Но в любом случае я придумал новый вариант:


class VIterator
{
public:
    bool    m_break;
    bool    m_end;
    VIterator(bool end)
        : m_break(false), m_end(end)
    {
    }
};

template <class TIterator>
class VIteratorImpl : public VIterator
{
public:
    TIterator    m_p;

    VIteratorImpl(TIterator p, TIterator pEnd)
        : m_p(p), VIterator(p == pEnd)
    {
    }
};

template <class TIterator>
inline VIteratorImpl<TIterator>    vIteratorInit(TIterator pStart, TIterator pEnd)
{
    return VIteratorImpl<TIterator>(pStart, pEnd);
}


template <class TIterator>
inline void    vIteratorStep(VIterator & pIter, TIterator pEnd)
{
    ++static_cast<VIteratorImpl<TIterator>& >(pIter).m_p;
}

template <class TIterator>
inline typename TIterator::reference vIteratorGetValue(VIterator & pIter, TIterator pEnd)
{
    pIter.m_break = true;
    TIterator::reference ret = *static_cast<VIteratorImpl<TIterator> & >(pIter).m_p;
    pIter.m_end = (pEnd == ++static_cast<VIteratorImpl<TIterator> & >(pIter).m_p);
    return ret;
}



#define FOREACH(varDef, collection)\
    for(\
        VIterator & pIterator = vIteratorInit(collection.begin(), collection.end());\
        !pIterator.m_end && !pIterator.m_break;\
        )\
        for(varDef = vIteratorGetValue(pIterator, collection.end()); pIterator.m_break; pIterator.m_break = false)
С уважением Вадим.
Re[4]: Могу предложить альтернативу
От: folk Россия  
Дата: 11.11.03 06:45
Оценка:
Здравствуйте, lboss, Вы писали:

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



F>>Я тоже думал над подобным вариантом. Но на всякий случай решил не _использовать_ результат аргумента Last на каждой итерации. Это мне показалось более безопасным. Также я допускал что это облегчит жизнь оптимайзеру.


F>>Опосля пришла мысль что лучше кастить к First, чем к Last, т.к. у тех реализаций контейнеров, что я видел, метод begin() устроен либо проще чем end(), либо они примерно одинаковы.


L>Ну я наоборот считаю end() более простой операцией — так как это же fake'овый объект как правило и его проще построить.



L>Но в любом случае я придумал новый вариант:



L>
L>class VIterator
L>{
L>public:
L>    bool    m_break;
L>    bool    m_end;
L>    VIterator(bool end)
L>        : m_break(false), m_end(end)
L>    {
L>    }
L>};

L>template <class TIterator>
L>class VIteratorImpl : public VIterator
L>{
L>public:
L>    TIterator    m_p;

L>    VIteratorImpl(TIterator p, TIterator pEnd)
L>        : m_p(p), VIterator(p == pEnd)
L>    {
L>    }
L>};

L>template <class TIterator>
L>inline VIteratorImpl<TIterator>    vIteratorInit(TIterator pStart, TIterator pEnd)
L>{
L>    return VIteratorImpl<TIterator>(pStart, pEnd);
L>}


L>template <class TIterator>
L>inline void    vIteratorStep(VIterator & pIter, TIterator pEnd)
L>{
L>    ++static_cast<VIteratorImpl<TIterator>& >(pIter).m_p;
L>}

L>template <class TIterator>
L>inline typename TIterator::reference vIteratorGetValue(VIterator & pIter, TIterator pEnd)
L>{
L>    pIter.m_break = true;
L>    TIterator::reference ret = *static_cast<VIteratorImpl<TIterator> & >(pIter).m_p;
L>    pIter.m_end = (pEnd == ++static_cast<VIteratorImpl<TIterator> & >(pIter).m_p);
L>    return ret;
L>}



L>#define FOREACH(varDef, collection)\
L>    for(\
L>        VIterator & pIterator = vIteratorInit(collection.begin(), collection.end());\
L>        !pIterator.m_end && !pIterator.m_break;\
L>        )\
L>        for(varDef = vIteratorGetValue(pIterator, collection.end()); pIterator.m_break; pIterator.m_break = false)
L>


И на это есть ответ
Я рассматривал подобный монолитный вариант, но мне подумалось что я смогу повторно использовать элементарные wrap/unwrap для другой задачи, так что в результате сделал на них и поместил их в namespace util (а не в _foreach как в опубликованном варианте).

А вообще это правильно, чем больше удается вынести из мароса в шаблон, тем лучше. В скопе цикла находятся меньше скрытых макросом переменных.
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[4]: Могу предложить альтернативу
От: folk Россия  
Дата: 11.11.03 06:51
Оценка:
Здравствуйте, lboss, Вы писали:

L>#define FOREACH(varDef, collection)\

L> for(\
L> VIterator & pIterator = vIteratorInit(collection.begin(), collection.end());\
L> !pIterator.m_end && !pIterator.m_break;\
L> )\
L> for(varDef = vIteratorGetValue(pIterator, collection.end()); pIterator.m_break; pIterator.m_break = false)
L>[/ccode]

Ты что ж творишь? Временное значение нельзя привязывать к неконстантной ссылке.
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[5]: Могу предложить альтернативу
От: e-Xecutor Россия  
Дата: 11.11.03 07:42
Оценка:
Здравствуйте, folk, Вы писали:

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

L>>#define FOREACH(varDef, collection)\
L>>    for(\
L>>        VIterator & pIterator = vIteratorInit(collection.begin(), collection.end());\
L>>        !pIterator.m_end && !pIterator.m_break;\
L>>        )\
L>>        for(varDef = vIteratorGetValue(pIterator, collection.end()); pIterator.m_break; pIterator.m_break = false)
L>>


F>Ты что ж творишь? Временное значение нельзя привязывать к неконстантной ссылке.

Это почему же?

#include <stdio.h>

class Base{
};

class Derived:public Base{
public:
  Derived(){printf("C\n");}
  Derived(const Derived& d){printf("CC\n");}
  ~Derived(){printf("D\n");}
};

Derived getD()
{
  return Derived();
}

int main(int argc,char* argv[])
{
  Base& b=getD();
  printf("hello!\n");
  return 0;
}


Вывод:
C
Hello
D

Re[3]: Крокодилы в клетке
От: Павел Кузнецов  
Дата: 11.11.03 07:51
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш>>> <... цитата из 5/4 ...>


Ш>>> стандарт относит это к unspecified behavior


ПК>> Хуже: undefined.


Ш> В таком случае попрошу поподробнее.

Ш> Почему в коментария написано unspecified (опечатка?).

Да, опечатка, даже defect report имеется:
http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/cwg_active.html#351

Ш> В чем разница между unspecified и undefined. Только не надо отсылать

Ш> к стандарту. У старенького дяди Шахтёра мозгА в этом стандарте не всё
Ш> понимает.

В этом стандарте по-настоящему никто все не понимает
Но в данном случае, вроде, есть надежда разобраться:
http://www.rsdn.ru/forum/Message.aspx?mid=215574
Автор: Павел Кузнецов
Дата: 17.03.03


P.S. по поводу std::transform — в отдельном сообщении, если будет время.
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[3]: No more ugly functors
От: dad  
Дата: 11.11.03 07:51
Оценка:
ЮБ>>Чем функторы то так не нравятся, рульно же когда цикл в одном месте а алгоритм в другом — нафига обртно все в кучу упихивать то?

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


зато использование таких супер макросов как у тебя чрезвычайно рульно..
Веру-ю-у! В авиацию, в научную революци-ю-у, в механизацию сельского хозяйства, в космос и невесомость! Веру-ю-у! Ибо это объективно-о! (Шукшин)
Re[6]: Могу предложить альтернативу
От: folk Россия  
Дата: 11.11.03 09:36
Оценка:
Здравствуйте, e-Xecutor, Вы писали:

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


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

EX>
L>>>#define FOREACH(varDef, collection)\
L>>>    for(\
L>>>        VIterator & pIterator = vIteratorInit(collection.begin(), collection.end());\
L>>>        !pIterator.m_end && !pIterator.m_break;\
L>>>        )\
L>>>        for(varDef = vIteratorGetValue(pIterator, collection.end()); pIterator.m_break; pIterator.m_break = false)
L>>>


F>>Ты что ж творишь? Временное значение нельзя привязывать к неконстантной ссылке.

EX>Это почему же?

EX>
EX>#include <stdio.h>

EX>class Base{
EX>};

EX>class Derived:public Base{
EX>public:
EX>  Derived(){printf("C\n");}
EX>  Derived(const Derived& d){printf("CC\n");}
EX>  ~Derived(){printf("D\n");}
EX>};

EX>Derived getD()
EX>{
EX>  return Derived();
EX>}

EX>int main(int argc,char* argv[])
EX>{
EX>  Base& b=getD();
EX>  printf("hello!\n");
EX>  return 0;
EX>}
EX>


EX>Вывод:

EX>C
EX>Hello
EX>D

EX>


8.5.3/5

A reference to type ``cv1 T1'' is initialized by an expression of type ``cv2 T2'' as follows:

If the initializer expression
— is an lvalue (but is not a bit-field), and ``cv1 T1'' is reference-compatible with ``cv2 T2,'' or
— has a class type (i.e., T2 is a class type) and can be implicitly converted to an lvalue of type ``cv3 T3,'' where ``cv1 T1'' is reference-compatible with ``cv3 T3'' *

[Footnote: This requires a conversion function (class.conv.fct) returning a reference type. --- end foonote]


Не уверен что правильно понял. Наше rvalue класс-типа может быть неявно преобразовано в lvalue?
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[5]: Могу предложить альтернативу
От: lboss Россия  
Дата: 11.11.03 09:56
Оценка:
Здравствуйте, folk, Вы писали:

F>Ты что ж творишь? Временное значение нельзя привязывать к неконстантной ссылке.


Тут ты не прав боюсь...

Тогда бы конструкции такого вида не работали бы:

  void f(A & val);
  
...
  f(A());
С уважением Вадим.
Re[5]: Могу предложить альтернативу
От: lboss Россия  
Дата: 11.11.03 10:00
Оценка:
Здравствуйте, folk, Вы писали:

F>И на это есть ответ

F>Я рассматривал подобный монолитный вариант, но мне подумалось что я смогу повторно использовать элементарные wrap/unwrap для другой задачи, так что в результате сделал на них и поместил их в namespace util (а не в _foreach как в опубликованном варианте).

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

F>А вообще это правильно, чем больше удается вынести из мароса в шаблон, тем лучше. В скопе цикла находятся меньше скрытых макросом переменных.


Вообще-то, по моему, главный принцип (или заслуга) данного подхода — это работающий break, и ясность реализации...
С уважением Вадим.
Re[6]: Могу предложить альтернативу
От: MaximE Великобритания  
Дата: 11.11.03 10:05
Оценка:
Здравствуйте, lboss, Вы писали:

L>Тогда бы конструкции такого вида не работали бы:


L>
L>  void f(A & val);
  
L>...
L>  f(A());
L>


Такие конструкции и не должны работать.

Это мелкософтовские студии такое позволяют. Если отключить "language extensions" в семерке, то такую ерунду уже не получится написать.

Удалено избыточное цитирование. -- ПК.
Censored, — ПК.
Re[7]: Могу предложить альтернативу
От: lboss Россия  
Дата: 11.11.03 10:34
Оценка:
Здравствуйте, MaximE, Вы писали:

ME>Такие конструкции и не должны работать.


ME>Это мелкософтовские студии такое позволяют. Если отключить "language extensions" в семерке, то такую ерунду уже не получится написать.


Ну ладно — это в конечном случае не принципиально. С моей точки зрения тут всё нормально ибо "const" это просто модификатор — сути он не меняет. Я считаю что запись:

   f(A());


Намного удобней, чем:
   {
     A tmp;
     f(tmp);
   }
С уважением Вадим.
Re[7]: Могу предложить альтернативу
От: e-Xecutor Россия  
Дата: 11.11.03 12:21
Оценка:
Здравствуйте, folk, Вы писали:

F>Не уверен что правильно понял. Наше rvalue класс-типа может быть неявно преобразовано в lvalue?

Однако ты прав.
То бишь не может.
То бишь код неправильный
А товарищи cl 7.1 и icl 7.1 тоже неправы, а g++ рулит

Таки rvalue может инициализировать только константную ссылку.
А объект возвращаемый функцией by value является rvalue.
Но! От него позволяется вызвать метод.
А если этот метод вернёт ссылку на него самого, то ею можно будет инициализировать
неконстантную ссылку
Re[8]: Могу предложить альтернативу
От: e-Xecutor Россия  
Дата: 11.11.03 12:28
Оценка:
EX>Но! От него позволяется вызвать метод.
EX>А если этот метод вернёт ссылку на него самого, то ею можно будет инициализировать
EX>неконстантную ссылку
Не, нельзя так делать, темпоральный объект помрёт
Re[3]: Крокодилы в клетке
От: Павел Кузнецов  
Дата: 11.11.03 14:32
Оценка:
Здравствуйте, Шахтер, Вы писали:

ЮБ>>
 ЮБ>> 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;
 ЮБ>> }
 ЮБ>>


Ш> В этом коде насколько оправдан вызов transform. Дело в том, что он читает

Ш> данные из того же массива, в который пишет.

Ничего страшного, более того, это явно разрешается стандартом:

25.2.3/5 Notes: result may be equal to first in case of unary transform,
or to first1 or first2in case of binary transform.


Ш> Стандарт вроде не определяет, в каком точно порядке transform работает.


Это определяется требованиями к алгоритму поддерживать работу с InputIterator.
Работа с InputIterator автоматически означает движение от начала к концу.

Ш> Может он откладывает запись, например.


Я не представляю, как это возможно сделать для OutputIterator, учитывая что
алгоритм не может возвращаться и копия OutputIterator не пригодна ни для
инкремента, ни для записи (*a = t) после того, как оригинал инкрементирован,
и наоборот.

Ш> Или вообще едет сверху вниз (это конечно маловероятно, но возможно).


Это невозможно: InputIterator не позволяет двигаться от конца к началу.

Ш> Или запускает несколько потоков на многопроцессорной системе.


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

Ш> Requires: op and binary_op shall not have any side effects.

Ш> Что эта фраза означает?

1.9/7 Accessing an object designated by a volatile lvalue (3.10),
modifying an object, calling a library I/O function, or calling a function
that does any of those operations are all side effects, which are changes
in the state of the execution environment.


Соответстенно, ничего из перечисленного op или binary_op делать не должны
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[4]: Крокодилы в клетке
От: Аноним  
Дата: 11.11.03 14:49
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

Ш>> Requires: op and binary_op shall not have any side effects.

Ш>> Что эта фраза означает?

ПК>

1.9/7 Accessing an object designated by a volatile lvalue (3.10),
ПК>modifying an object, calling a library I/O function, or calling a function
ПК>that does any of those operations are all side effects, which are changes
ПК>in the state of the execution environment.


ПК>Соответстенно, ничего из перечисленного op или binary_op делать не должны


Т.е. изменять свое внутреннее состояние они не могут?
Re[5]: Крокодилы в клетке
От: Павел Кузнецов  
Дата: 11.11.03 15:03
Оценка:
Здравствуйте, , Вы писали:

Ш>>> Requires: op and binary_op shall not have any side effects.

Ш>>> Что эта фраза означает?

ПК>> <...>


> Т.е. изменять свое внутреннее состояние они не могут?


Не могут. Например, гарантий, что функтор не будет копироваться, нет.
В этом аспекте приведенный код формально неверен. Правда, сомневаюсь,
что на практике хотя бы одна реализация стандартной библиотеки не будет
работать с данным функтором.
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[6]: Крокодилы в клетке
От: Юнусов Булат Россия  
Дата: 11.11.03 15:55
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:


ПК>Не могут. Например, гарантий, что функтор не будет копироваться, нет.

ПК>В этом аспекте приведенный код формально неверен. Правда, сомневаюсь,
ПК>что на практике хотя бы одна реализация стандартной библиотеки не будет
ПК>работать с данным функтором.

Да, для правильности (тот же Мейерс Effective STL), надо было конструктор копирования приписать, поленился, там еще и проверок нет скажем на нульность агрумента конструктора и на выход за границы массива.
Re[7]: Крокодилы в клетке
От: Павел Кузнецов  
Дата: 11.11.03 15:58
Оценка:
Здравствуйте, Юнусов, Вы писали:

ПК>> Не могут. Например, гарантий, что функтор не будет копироваться, нет.


ЮБ> Да, для правильности (тот же Мейерс Effective STL), надо было конструктор

ЮБ> копирования приписать

А как бы он помог в данном случае, если бы для одной части диапазона
использовалась одна копия, а для другой — другая?
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[8]: Крокодилы в клетке
От: Юнусов Булат Россия  
Дата: 11.11.03 16:32
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>А как бы он помог в данном случае, если бы для одной части диапазона

ПК>использовалась одна копия, а для другой — другая?

А как такое может случится?
Re[9]: Крокодилы в клетке
От: Павел Кузнецов  
Дата: 11.11.03 16:45
Оценка:
Здравствуйте, Юнусов, Вы писали:

ПК>> А как бы он помог в данном случае, если бы для одной части диапазона

ПК>> использовалась одна копия, а для другой — другая?

ЮБ> А как такое может случится?


Я тоже очень сомневаюсь в практической осуществимости подобного, но формально
ничто в стандарте не запрещает реализации сделать такую гадость Собственно,
я полагаю, что авторы стандарта, решив не тратить усилия на формулировки того,
какие именно побочные эффекты запрещены, на всякий случай перестраховались,
добавив требование отсутствия любых.
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[10]: Крокодилы в клетке
От: Павел Кузнецов  
Дата: 11.11.03 17:27
Оценка: 10 (1)
Здравствуйте, Павел, Вы писали:

ПК> Собственно, я полагаю, что авторы стандарта, решив не тратить усилия

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

Ага... Дальнейшее разбирательство показало, что имеется library defect report
http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/lwg-defects.html#242 , который как
раз касается побочных эффектов стандартных алгоритмов, включая и std::transform.
Текущее предложение относительно побочных эффектов std::transform выглядит так:

Requires: op and binary_op shall not invalidate iterators or subranges, or modify
elements in the ranges [first1, last1], [first2, first2 + (last1 — first1)],
and [result, result + (last1 -first1)].
[Footnote: The use of fully closed ranges is intentional --end footnote]

Соответственно, наши нынешние практические ожидания подтверждаются дальнейшими
изысканиями формалистов-стандартизаторов
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[11]: Крокодилы в клетке
От: Юнусов Булат Россия  
Дата: 11.11.03 18:06
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>

Requires: op and binary_op shall not invalidate iterators or subranges, or modify
ПК>elements in the ranges [first1, last1], [first2, first2 + (last1 — first1)],
ПК>and [result, result + (last1 -first1)].
ПК>[Footnote: The use of fully closed ranges is intentional --end footnote]

ПК>Соответственно, наши нынешние практические ожидания подтверждаются дальнейшими
ПК>изысканиями формалистов-стандартизаторов

значит выделенный код будет считатся неверным
    miner(int * data) : data_(data), i_(0) { data_[0] = data_[1] = 1; }

он правда там и так лишний по большому счету
Re[12]: Крокодилы в клетке
От: Павел Кузнецов  
Дата: 11.11.03 20:25
Оценка:
Здравствуйте, Юнусов Булат, Вы писали:

ПК>>

Requires: op and binary_op shall not invalidate iterators or subranges, or modify
ПК>>elements in the ranges [first1, last1], [first2, first2 + (last1 — first1)],
ПК>>and [result, result + (last1 -first1)].
ПК>>[Footnote: The use of fully closed ranges is intentional --end footnote]


ЮБ>значит выделенный код будет считатся неверным

ЮБ>
ЮБ>    miner(int * data) : data_(data), i_(0) { data_[0] = data_[1] = 1; } 
ЮБ>

ЮБ>он правда там и так лишний по большому счету

С этим кодом и было, и будет все в порядке: конструирование функтора никак не взаимодействует с дальнейшим выполнением std::transform. В процитированном фрагменте речь шла о побочных эффектах внутри operator(). В текущей редакции стандарта запрещены любые побочные эффекты, в том числе и модификация данных-членов функтора. Предложенное исправление, вошедшее в текущий черновик, данное — имхо, чисто теоретическое — ограничение снимает.
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[6]: Могу предложить альтернативу
От: folk Россия  
Дата: 11.11.03 22:47
Оценка:
Здравствуйте, lboss, Вы писали:

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


F>>И на это есть ответ

F>>Я рассматривал подобный монолитный вариант, но мне подумалось что я смогу повторно использовать элементарные wrap/unwrap для другой задачи, так что в результате сделал на них и поместил их в namespace util (а не в _foreach как в опубликованном варианте).

L>Не понял аргументации — ибо для практически любой другой задачи проще итераторами пользоваться всё-таки... по моему...


Тоже не понял... Что есть практически любая задача? Я совершенно не имел ввиду итераторы/контейнеры...

F>>А вообще это правильно, чем больше удается вынести из мароса в шаблон, тем лучше. В скопе цикла находятся меньше скрытых макросом переменных.


L>Вообще-то, по моему, главный принцип (или заслуга) данного подхода — это работающий break, и ясность реализации...


Ну с break то все давно решено. А насчет ясности ты наверное прав.
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[4]: Крокодилы в клетке
От: Шахтер Интернет  
Дата: 12.11.03 00:55
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

Ш>> В этом коде насколько оправдан вызов transform. Дело в том, что он читает

Ш>> данные из того же массива, в который пишет.

ПК>Ничего страшного, более того, это явно разрешается стандартом:

ПК>

ПК>25.2.3/5 Notes: result may be equal to first in case of unary transform,
ПК>or to first1 or first2in case of binary transform.


Ш>> Стандарт вроде не определяет, в каком точно порядке transform работает.


ПК>Это определяется требованиями к алгоритму поддерживать работу с InputIterator.

ПК>Работа с InputIterator автоматически означает движение от начала к концу.

Здесь не всё так просто. И вот почему. Реализация библиотеки может предоставлять специализации алгоритма для различных типов функторов. Более того, насколько я понимаю, это и делается (нужно посмотреть исходники, сейчас у меня на это просто нет времени). В этом коде итераторы -- это указатели, значит, для них те трюки, которые я описал, вполне возможны. Стандарт, насколько я понимаю, всё-таки не определяет точно порядок выполнения преобразований. Он определяет только что будет аргументом, и куда кладутся результаты преобразований. Для ясности, есть две последовательности x1,...,xn y1,...,yn. transform делает последовательность преобразований y1=f(x1),...,yn=f(xn). Но вот порядок, на самом деле, явно не продекларирован. Т.е. может быть и
yn=f(xn),...,y1=f(x1). Или ещё как-то. В данном же конкретно случае этот порядок принципиально важен -- иначе не будет работать. Замечание, приведённое выше, не по существу, т.к. оно верно, если нет связи между последовательностью операций, в нашем же случае такая связь есть. У нас же вычисление рекурсивной последовательности.
Между прочим, не так уж сложно написать библиотечку извращённых реализаций алгоритмов. Она может оказать неоценимую помощь при ловле вот таких тонких ситуаций.
... << RSDN@Home 1.1 beta 2 >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[5]: Крокодилы в клетке
От: Павел Кузнецов  
Дата: 12.11.03 09:43
Оценка:
Здравствуйте, Шахтер, Вы писали:

ПК>> Это определяется требованиями к алгоритму поддерживать работу с InputIterator.

ПК>> Работа с InputIterator автоматически означает движение от начала к концу.

Ш> Здесь не всё так просто. И вот почему. Реализация библиотеки может

Ш> предоставлять специализации алгоритма для различных типов функторов.

Теоретически — возможно. Практически — не представляю, зачем нужна специализация
std::transform, скажем, для random access iterators. Разве что специально для того,
чтобы "навернуть" функционал Юнуса Булатова Формально, ты, конечно, прав.

Ш> Стандарт, насколько я понимаю, всё-таки не определяет точно порядок выполнения

Ш> преобразований. Он определяет только что будет аргументом, и куда кладутся
Ш> результаты преобразований.

Для некоторых алгоритмов определяет (например, std::for_each).
Но, вообще, по этому поводу тоже defect report имеется, и даже не один:
http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/lwg-active.html#92
http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/lwg-active.html#290

Даже конкретно по поводу порядка в std::transform есть:
http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/lwg-closed.html#293

Ш> В данном же конкретно случае этот порядок принципиально важен -- иначе не будет

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

Согласен. В принципе, имхо, более удачным решением в данном случае было бы
использование, например, std::for_each.
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re: No more ugly functors
От: Аноним  
Дата: 12.11.03 11:43
Оценка:
Здравствуйте, folk, Вы писали:

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

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

А можно ли данный FOR_EACH с std::map использовать ?
Re: No more ugly functors
От: Аноним  
Дата: 12.11.03 12:26
Оценка:
Здравствуйте, folk, Вы писали:

F>#define FOR_EACH_(Decl, First, Last) \

F>if (false) {} else /*VC6 for-init-scope bug workaround*/ \

А что это за баг такой и зачем здесь его надо обходить ?
Re[2]: No more ugly functors
От: jazzer Россия Skype: enerjazzer
Дата: 12.11.03 12:52
Оценка:
Здравствуйте, Аноним, Вы писали:

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


F>>#define FOR_EACH_(Decl, First, Last) \

F>>if (false) {} else /*VC6 for-init-scope bug workaround*/ \

А>А что это за баг такой и зачем здесь его надо обходить ?


баг в том, что в for(int i;); i видна после цикла, а по Стандарту она должна быть видна только внутри цикла
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[3]: No more ugly functors
От: Аноним  
Дата: 12.11.03 13:09
Оценка:
Здравствуйте, jazzer, Вы писали:

J>Здравствуйте, Аноним, Вы писали:


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


F>>>#define FOR_EACH_(Decl, First, Last) \

F>>>if (false) {} else /*VC6 for-init-scope bug workaround*/ \

А>>А что это за баг такой и зачем здесь его надо обходить ?


J>баг в том, что в for(int i;); i видна после цикла, а по Стандарту она должна быть видна только внутри цикла


А в данном случае как это мешает ?
Re[4]: No more ugly functors
От: jazzer Россия Skype: enerjazzer
Дата: 12.11.03 13:17
Оценка:
Здравствуйте, Аноним, Вы писали:

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


J>>Здравствуйте, Аноним, Вы писали:


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


F>>>>#define FOR_EACH_(Decl, First, Last) \

F>>>>if (false) {} else /*VC6 for-init-scope bug workaround*/ \

А>>>А что это за баг такой и зачем здесь его надо обходить ?


J>>баг в том, что в for(int i;); i видна после цикла, а по Стандарту она должна быть видна только внутри цикла


А>А в данном случае как это мешает ?


Очень просто — напиши два FOR_EACH подряд, и получишь нарушение ODR по переменной _fe_cur.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: No more ugly functors
От: Аноним  
Дата: 14.11.03 11:53
Оценка:
Здравствуйте, Аноним, Вы писали:

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


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

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

А>А можно ли данный FOR_EACH с std::map использовать ?


Вот так не работает, к сожалению

FOR_EACH( pair<string,string>& i, mapStoS )
Re[3]: No more ugly functors
От: folk Россия  
Дата: 14.11.03 13:15
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Аноним, Вы писали:


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


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

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

А>>А можно ли данный FOR_EACH с std::map использовать ?


А>Вот так не работает, к сожалению


А>
А>FOR_EACH( pair<string,string>& i, mapStoS )
А>


Здесь у нас одна ошибка и одна проблема.

Ошибка: правильно будет:
FOR_EACH( pair<const string,string>& i, mapStoS )

Проблема: препроцессор понимает запятую между string и string как разделитель аргументов макроса и ругается что макрос FOR_EACH не берет 3 аргумента.
Интересно что я до сих пор не сталкивался с такой проблемой, т.к. всегда пользуюсь value_type. Например:

typedef std::map<std::string, std::string> mapStoS_t;
mapStoS_t mapStoS;
...
FOR_EACH(mapStoS_t::value_type& i, mapStoS) ...
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[4]: No more ugly functors
От: alexander_v Германия  
Дата: 19.11.03 09:06
Оценка:
Здравствуйте, folk, Вы писали:


А>>Вот так не работает, к сожалению


А>>
А>>FOR_EACH( pair<string,string>& i, mapStoS )
А>>



F>Проблема: препроцессор понимает запятую между string и string как разделитель аргументов макроса и ругается что макрос FOR_EACH не берет 3 аргумента.

F>Интересно что я до сих пор не сталкивался с такой проблемой, т.к. всегда пользуюсь value_type. Например:

F>
F>typedef std::map<std::string, std::string> mapStoS_t;
F>mapStoS_t mapStoS;
F>...
F>FOR_EACH(mapStoS_t::value_type& i, mapStoS) ...
F>


Я считаю, что явно указывать тип переменной в заголовке цикла — лучше т.к. нагляднее демонстрирует по элементам какого типа будем проводить итерации ( контейнер может быть объявлен очень далеко от цикла ).

Предлагаю следующее решение относительно map :


#define CONCAT( p1, p2 )  p1##,##p2
#define FOR_EACH_M( Decl_p1, Decl_p2, Cont )  FOR_EACH( CONCAT( Decl_p1, Decl_p2 ), Cont )

// Использовать так 
FOR_EACH_M( pair<const string, string>& thePair, mapStoS )


PS. Жалко что макросы нельзя перегружать — тогда можно было бы не выдумывать новое имя FOR_EACH_M
Re[5]: No more ugly functors
От: dad  
Дата: 19.11.03 18:27
Оценка:
_>
_>#define CONCAT( p1, p2 )  p1##,##p2
_>#define FOR_EACH_M( Decl_p1, Decl_p2, Cont )  FOR_EACH( CONCAT( Decl_p1, Decl_p2 ), Cont )

_>// Использовать так 
_>FOR_EACH_M( pair<const string, string>& thePair, mapStoS )

_>


_>PS. Жалко что макросы нельзя перегружать — тогда можно было бы не выдумывать новое имя FOR_EACH_M


мне кажется что такой код не только не красивый, но и неправильный..
Веру-ю-у! В авиацию, в научную революци-ю-у, в механизацию сельского хозяйства, в космос и невесомость! Веру-ю-у! Ибо это объективно-о! (Шукшин)
Re[6]: No more ugly functors
От: alexander_v Германия  
Дата: 20.11.03 07:08
Оценка:
Здравствуйте, dad, Вы писали:


_>>
_>>#define CONCAT( p1, p2 )  p1##,##p2
_>>#define FOR_EACH_M( Decl_p1, Decl_p2, Cont )  FOR_EACH( CONCAT( Decl_p1, Decl_p2 ), Cont )

_>>// Использовать так 
_>>FOR_EACH_M( pair<const string, string>& thePair, mapStoS )

_>>


_>>PS. Жалко что макросы нельзя перегружать — тогда можно было бы не выдумывать новое имя FOR_EACH_M


dad>мне кажется что такой код не только не красивый, но и неправильный..


В чем неправильность ?
Re[7]: No more ugly functors
От: dad  
Дата: 20.11.03 07:22
Оценка:
_>>>PS. Жалко что макросы нельзя перегружать — тогда можно было бы не выдумывать новое имя FOR_EACH_M

dad>>мне кажется что такой код не только не красивый, но и неправильный..


_>В чем неправильность ?


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

в этом же случае вообще просматривается попытка использовать макрос как конструкцию языка на подобие функции. что в корне не правильно даже для макроса!
если такая уж нужна — напиши функцию и используй ее зачем макрос то?и потом — такая беда практически не поддается отладке.
Веру-ю-у! В авиацию, в научную революци-ю-у, в механизацию сельского хозяйства, в космос и невесомость! Веру-ю-у! Ибо это объективно-о! (Шукшин)
Re[3]: No more ugly functors
От: yxiie Украина www.enkord.com
Дата: 04.06.04 12:51
Оценка:
Здравствуйте, WolfHound, Вы писали:

[]


WolfHound,
Очень клевый foreach, спасибо, вот только у меня VC7.0 спотыкается о:

> //Реализация для массивов

> template<class value_t, size_t size_n>
> struct container_traits<value_t[size_n]>

пишет:

F:\Work\prg\unnamed\include\0-utility\lang>cl a.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.00.9466 for 80x86
Copyright (C) Microsoft Corporation 1984-2001. All rights reserved.

a.cpp
a.cpp(43) : error C2065: 'value_t' : undeclared identifier
a.cpp(43) : error C2065: 'size_n' : undeclared identifier


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

Кстати вопрос к тем, кто использовал этот foreach:

за это прошедшее время нашли какие-нибудь ошибки или негативное воздействие
на производительность? Может быть есть какие-то усовершенствования над этим foreach?
Думаю за это время многие уже успели его хорошо обкатать и использовать в деле. Какие отзывы?
Re[4]: No more ugly functors
От: WolfHound  
Дата: 04.06.04 13:40
Оценка:
Здравствуйте, yxiie, Вы писали:

Y>Очень клевый foreach, спасибо, вот только у меня VC7.0 спотыкается о:


>> //Реализация для массивов

>> template<class value_t, size_t size_n>
>> struct container_traits<value_t[size_n]>
VC++7.0 не поддерживает частичную специализацию... тут я тебе ни чем помеч не могу. Переходи на VC++7.1 там работает.
... << RSDN@Home 1.1.3 beta 1 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[5]: No more ugly functors
От: yxiie Украина www.enkord.com
Дата: 04.06.04 14:45
Оценка:
Здравствуйте, WolfHound, Вы писали:

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


Y>>Очень клевый foreach, спасибо, вот только у меня VC7.0 спотыкается о:


>>> //Реализация для массивов

>>> template<class value_t, size_t size_n>
>>> struct container_traits<value_t[size_n]>
WH>VC++7.0 не поддерживает частичную специализацию... тут я тебе ни чем помеч не могу. Переходи на VC++7.1 там работает.

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

Кстати, с какой версии _MSC_VER VC++ поддерживает частичную специализацию?
Re[6]: No more ugly functors
От: Павел Кузнецов  
Дата: 06.06.04 18:38
Оценка:
> А как с частичной специализацией и других компиляторов на других платформах?

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

> Кстати, с какой версии _MSC_VER VC++ поддерживает частичную специализацию?


7.1
Posted via RSDN NNTP Server 1.9 alpha
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[6]: No more ugly functors
От: alexkro  
Дата: 06.06.04 22:41
Оценка:
Здравствуйте, yxiie, Вы писали:

Y>Кстати, с какой версии _MSC_VER VC++ поддерживает частичную специализацию?


_MSC_VER == 1310
Re[3]: No more ugly functors
От: Lexey Россия  
Дата: 22.11.04 15:55
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>ЗЫ ИМХО container_traits (ну если еще доработать) самое место в STL. Что скажите?


Что-то мне кажется, что в boost.range (1.32) это уже сделали.
Re[4]: No more ugly functors
От: folk Россия  
Дата: 23.11.04 00:21
Оценка:
Здравствуйте, Lexey, Вы писали:

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


WH>>ЗЫ ИМХО container_traits (ну если еще доработать) самое место в STL. Что скажите?


L>Что-то мне кажется, что в boost.range (1.32) это уже сделали.


Ладно тебе, это было сказано за год до выхода 1.32

А сейчас действительно можно переписать FOR_EACH так, чтобы он использовал boost::begin()/boost::end() и вообще убрать поддержку пары итераторов — вместо них лучше использовать boost::make_iterator_range() или std::make_pair().
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[5]: No more ugly functors
От: folk Россия  
Дата: 23.11.04 01:51
Оценка:
Здравствуйте, folk, Вы писали:

F>А сейчас действительно можно переписать FOR_EACH так, чтобы он использовал boost::begin()/boost::end() и вообще убрать поддержку пары итераторов — вместо них лучше использовать boost::make_iterator_range() или std::make_pair().


Переписал. Аргумент макроса Range принимает все, c чем может работать boost::range:

standard-like containers
std::pair<iterator,iterator>
null terminated strings (this includes char[],wchar_t[], char*, and wchar_t*)
built-in arrays

#pragma once
#include "boost/range/result_iterator.hpp"
#include "boost/range/begin.hpp"
#include "boost/range/end.hpp"

namespace foreach_detail {

template<typename> struct wrapper;

// Range means SinglePassRange

struct holder
{
    template<class Range>
    typename boost::range_result_iterator<Range>::type&
        operator()( Range& ) const
    {
        typedef typename boost::range_result_iterator<Range>::type iterator;
        return static_cast<wrapper<iterator> const&>(*this).iterator_;
    }
};

template<typename Iterator>
struct wrapper : holder
{
    wrapper( Iterator iterator )
        : iterator_( iterator )
    {}
 
 private:
 friend struct holder;
    mutable Iterator iterator_;
};

template<class Range>
wrapper<typename boost::range_result_iterator<Range>::type>
    begin( Range& range )
{
    return boost::begin( range );
}

template<class Range>
wrapper<typename boost::range_result_iterator<Range>::type>
    end( Range& range )
{
    return boost::end( range );
}

} // namespace foreach_detail

#define FOR_EACH( ElementDecl, Range )\
    if( bool _fe_break = false ) {}\
    else\
    for( foreach_detail::holder const\
              &_fe_current = foreach_detail::begin(Range)\
            , &_fe_last    = foreach_detail::end(Range)\
        ; _fe_current(Range) != _fe_last(Range) && (_fe_break = !_fe_break)\
        ; ++_fe_current(Range)\
    )\
    for( ElementDecl = *_fe_current(Range); _fe_break; _fe_break = false )\
// end macro
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[6]: No more ugly functors
От: folk Россия  
Дата: 23.11.04 04:14
Оценка: 6 (1)
Здравствуйте, folk, Вы писали:

Работа над ошибками.
Было задумано так, что в аргумент Range макроса можно передавать std::make_pair(ptr,ptr). Тут есть проблема — результат make_pair является rvalue, а значит по стандарту не может приниматься функцией по неконстантной ссылке. Предыдущая версия этим не озаботилась, т.к. VC запросто принимает rvalue по неконстантной ссылке.
Исправлено, теперь каждая функция перегружена для константной ссылки.
#pragma once
#include "boost/range/iterator.hpp"
#include "boost/range/const_iterator.hpp"
#include "boost/range/begin.hpp"
#include "boost/range/end.hpp"

namespace foreach_detail {

template<typename> struct wrapper;

// Range means SinglePassRange

struct holder
{
    template<class Range>
    typename boost::range_iterator<Range>::type&
        operator()( Range& ) const
    {
        typedef typename boost::range_iterator<Range>::type iterator;
        return static_cast<wrapper<iterator> const&>(*this).iterator_;
    }

    template<class Range>
    typename boost::range_const_iterator<Range>::type&
        operator()( Range const& ) const
    {
        typedef typename boost::range_const_iterator<Range>::type iterator;
        return static_cast<wrapper<iterator> const&>(*this).iterator_;
    }
};

template<typename Iterator>
struct wrapper : holder
{
    wrapper( Iterator iterator )
        : iterator_( iterator )
    {}
 
 private:
 friend struct holder;
    mutable Iterator iterator_;
};

template<class Range>
wrapper<typename boost::range_iterator<Range>::type>
    begin( Range& range )
{
    return boost::begin( range );
}

template<class Range>
wrapper<typename boost::range_const_iterator<Range>::type>
    begin( Range const& range )
{
    return boost::begin( range );
}

template<class Range>
wrapper<typename boost::range_iterator<Range>::type>
    end( Range& range )
{
    return boost::end( range );
}

template<class Range>
wrapper<typename boost::range_const_iterator<Range>::type>
    end( Range const& range )
{
    return boost::end( range );
}

} // namespace foreach_detail

#define FOR_EACH( ElementDecl, Range )\
    if( bool _fe_break = false ) {}\
    else\
    for( foreach_detail::holder const\
              &_fe_current = foreach_detail::begin(Range)\
            , &_fe_last    = foreach_detail::end(Range)\
        ; _fe_current(Range) != _fe_last(Range) && (_fe_break = !_fe_break)\
        ; ++_fe_current(Range)\
    )\
    for( ElementDecl = *_fe_current(Range); _fe_break; _fe_break = false )\
// end macro
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re: No more ugly functors
От: Аноним  
Дата: 23.11.04 06:35
Оценка:
Здравствуйте, folk, Вы писали:

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

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

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

дело вкуса, я юзаю STL и BOOST мне хватает.
советую глянуть лямбда-вычисления, некая замена безымянных функторов:

// ПРИМЕРЫ ИЗ ДОКУМЕНТАЦИИ
for_each(a.begin(), a.end(), std::cout << _1 << '\n');
for_each(a.begin(), a.end(), cout << ++var(index) << ':' << _1 << '\n');
// ну или так
for_each(a.begin(), a.end(), if_(_1 % 2 == 0)[ cout << _1 ]);
// или цикл
int a[5][10]; int i;
for_each(a, a+5, 
  for_loop(var(i)=0, var(i)<10, ++var(i), 
           _1[var(i)] += 1));


возможные конструкции
if_then(condition, then_part)
if_then_else(condition, then_part, else_part)
if_then_else_return(condition, then_part, else_part)
while_loop(condition, body)
while_loop(condition) // no body case
do_while_loop(condition, body)
do_while_loop(condition) // no body case 
for_loop(init, condition, increment, body)
for_loop(init, condition, increment) // no body case
switch_statement(...)


плюс можно биндить функции или функторы
int foo(int);
for_each(v.begin(), v.end(), _1 = bind(foo, _1));
Re[2]: No more ugly functors
От: folk Россия  
Дата: 23.11.04 07:27
Оценка:
Здравствуйте, Аноним, Вы писали:

А>дело вкуса, я юзаю STL и BOOST мне хватает.

А>советую глянуть лямбда-вычисления, некая замена безымянных функторов

[]

std::for_each + boost::lambda, std::for_each + явный функтор, явный цикл, FOR_EACH — можно использовать что угодно, лишь бы было удобно и не было войны.
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[2]: No more ugly functors
От: vdimas Россия  
Дата: 23.11.04 12:25
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Но при использовании break оптимизатор не смог избавится от оверхеда


естественно, потому как логика изменения переменной _fe_break заранее не известна в случае применения break. Если сделать допущение и разделить аргументы типа и переменной, т.е. так:
foreach(int, i, vec) { ... }


то последней конструкцией не будет for (где мы подставляли объявление "int i"), и тогда break и continue работают естественным образом, без оверхеда.

вот болванка:

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);

    int s=0;

    if(bool _fe_break=false) {} else
        for(int i;_fe_break==false; _fe_break=true)    // тут просто объявили
            for(const foreach_detail::wrapper_holder
                &_fe_cur=foreach_detail::wrap(v.begin()),
                &_fe_end=foreach_detail::wrap(v.end());
                !foreach_detail::is_wrapped_equal(_fe_cur, _fe_end, v.end());
                ++foreach_detail::unwrap(_fe_cur, v.end()))
                    if(i=*foreach_detail::unwrap(_fe_cur, v.end()), true)  // тут if а не for
    {
        if(i==2) break;
        s+=i;
    }

    std::cout <<s;
    return 0;
}


break и continue в ассемблерном листинге без оверхеда.
Re[3]: No more ugly functors
От: folk Россия  
Дата: 23.11.04 23:11
Оценка: +1
Здравствуйте, vdimas, Вы писали:

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


WH>>Но при использовании break оптимизатор не смог избавится от оверхеда


V>естественно, потому как логика изменения переменной _fe_break заранее не известна в случае применения break. Если сделать допущение и разделить аргументы типа и переменной, т.е. так:

V>
V>foreach(int, i, vec) { ... }
V>


V>то последней конструкцией не будет for (где мы подставляли объявление "int i"), и тогда break и continue работают естественным образом, без оверхеда.


V>вот болванка:


V>
V>int _tmain(int argc, _TCHAR* argv[])
V>{

V>    std::vector<int> v;
V>    v.push_back(1);
V>    v.push_back(2);
V>    v.push_back(3);
V>    v.push_back(4);

V>    int s=0;

V>    if(bool _fe_break=false) {} else
V>        for(int i;_fe_break==false; _fe_break=true)    // тут просто объявили
V>            for(const foreach_detail::wrapper_holder
V>                &_fe_cur=foreach_detail::wrap(v.begin()),
V>                &_fe_end=foreach_detail::wrap(v.end());
V>                !foreach_detail::is_wrapped_equal(_fe_cur, _fe_end, v.end());
V>                ++foreach_detail::unwrap(_fe_cur, v.end()))
V>                    if(i=*foreach_detail::unwrap(_fe_cur, v.end()), true)  // тут if а не for
V>    {
V>        if(i==2) break;
V>        s+=i;
V>    }

V>    std::cout <<s;
V>    return 0;
V>}
V>


V>break и continue в ассемблерном листинге без оверхеда.


Во-1х вводится лишняя запятая в объявлении макроса, а мы хотим синтаксически приблизится к "нормальному" foreach.

Во-2х такой подход принципиально не прет. Мы хотим иметь возможность объявлять ссылку на элемент последовательности ( FOR_EACH(int& i, vec) ) чтобы изменять эти элементы. А ссылку нельзя переназначить на другой элемент. Значит курсор (не знаю как его правильно обозвать) нельзя отдельно объявлять и отдельно присваивать значение. Объявление курсора не может находиться в if, т.к. неизвестно будет ли тип кусора неявно приводим к bool, а тем более будет ли приводим конкретно к true.

Написал путано, но попробуй сделать чтобы твой подход работал и со ссылками, и все станет ясно. По-моему (и WH видимо также считал) for — единственная подходящая конструкция для объявления курсора.
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[4]: No more ugly functors
От: vdimas Россия  
Дата: 24.11.04 13:58
Оценка: -1
Здравствуйте, folk, Вы писали:

F>Во-1х вводится лишняя запятая в объявлении макроса, а мы хотим синтаксически приблизится к "нормальному" foreach.


For Each пришел из VB, вообще-то, там это записывалось так:
Dim i as Integer
For Each i in col
' ...
Next


т.е. так же можно вынести объявление и в С++:
int i;
foreach(i, vec) s+=i;



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


все ясно, тут не возразишь...
но мне чисто внутренне приятней иметь 3 ассемблерные инструкции для организации цикла, вместо 6-ти (при использовании break)

свой вариант я уже оформил и именно в том виде, как показал выше — с предварительным объявлением.
Ok, беру ваш вариант, и называю его foreach_ref для тех случаев, где потребуется ссылка. (просто у меня чаще всего в коллекциях указатели хранятся, или их браться smart_ptr<они же>, т.е. я про ссылки не учел)

F>Объявление курсора не может находиться в if, т.к. неизвестно будет ли тип кусора неявно приводим к bool, а тем более будет ли приводим конкретно к true.


там у меня не объявление курсора, а присвоение. через запятую у меня там true.

Если бы была допустима такая конструкция:
if((int i=*it), true) {}
но она не допустима
Re[5]: No more ugly functors
От: folk Россия  
Дата: 25.11.04 02:31
Оценка:
Здравствуйте, vdimas, Вы писали:

V>все ясно, тут не возразишь...

V>но мне чисто внутренне приятней иметь 3 ассемблерные инструкции для организации цикла, вместо 6-ти (при использовании break)

Ага, не очень приятно это осозновать, но имхо break используется раз в пятилетку.

V>свой вариант я уже оформил и именно в том виде, как показал выше — с предварительным объявлением.

V>Ok, беру ваш вариант, и называю его foreach_ref для тех случаев, где потребуется ссылка. (просто у меня чаще всего в коллекциях указатели хранятся, или их браться smart_ptr<они же>, т.е. я про ссылки не учел)

На всякий случай замечу, что создание копии умного указателя скорее всего обойдется дороже, чем принять его по константной ссылке и (если используется break) потратить вхолостую эти три инструкции.
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[6]: No more ugly functors
От: yxiie Украина www.enkord.com
Дата: 25.11.04 08:37
Оценка:
Здравствуйте, folk, Вы писали:

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


V>>все ясно, тут не возразишь...

V>>но мне чисто внутренне приятней иметь 3 ассемблерные инструкции для организации цикла, вместо 6-ти (при использовании break)

F>Ага, не очень приятно это осозновать, но имхо break используется раз в пятилетку.


я поражаюсь люди, откуда такие сведения???
я, например, заметил за собой довольной частое использование. откуда статистика?
... << RSDN@Home 1.1.3 stable >>
Re[7]: No more ugly functors
От: folk Россия  
Дата: 25.11.04 12:00
Оценка:
yxiie:

> F>Ага, не очень приятно это осозновать, но имхо break используется раз в пятилетку.

>
> я поражаюсь люди, откуда такие сведения???
> я, например, заметил за собой довольной частое использование. откуда статистика?

это была метафора, художественное преувеличение

Сейчас поискал по текущему проекту, нашел 192 looping statement и 77 break, из них 66 находятся внутри switch. Получаем 192/11, т.е. 1 break на 17.(45) циклов.

Понятно что эти цифры ни о чем кроме этого самого проекта не говорят. Просто самому интересно стало.
Posted via RSDN NNTP Server 1.9 gamma
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[6]: No more ugly functors
От: vdimas Россия  
Дата: 28.11.04 01:50
Оценка:
Здравствуйте, folk, Вы писали:

F>На всякий случай замечу, что создание копии умного указателя скорее всего обойдется дороже, чем принять его по константной ссылке и (если используется break) потратить вхолостую эти три инструкции.


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

break я слишком часто юзаю, почти в 1/3 случаев. с ним алгоритмы самые короткие.
Re[7]: No more ugly functors
От: folk Россия  
Дата: 28.11.04 09:24
Оценка:
vdimas:

> F>На всякий случай замечу, что создание копии умного указателя скорее всего обойдется дороже, чем принять его по константной ссылке и (если используется break) потратить вхолостую эти три инструкции.

>
> На всякий случай замечу, что пройтись по коллекции с умными указателями всегда удавалось обычным указателем

Зависит от указателей, которые используешь. Бустовые умные не приводимы к "глупому" указателю, надо использовать get(). Так что с ними в FOR_EACH придется создавать копию.

> break я слишком часто юзаю, почти в 1/3 случаев. с ним алгоритмы самые короткие.
Posted via RSDN NNTP Server 1.9 delta
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[7]: No more ugly functors
От: yxiie Украина www.enkord.com
Дата: 14.01.05 19:03
Оценка:
Здравствуйте, folk, Вы писали:

Ну что за беда у меня с этими foreach
вариант WolfHound'a время от времени выдает run-time check failure — stack around 'xxx' variable corrupted,
у меня подозрения, что он пропускает больше прогонов цикла, чем нужно, а твой вариант
даже не компилится VC 7.0

f:\...xxx.cpp(24) : error C2667: 'foreach_detail::begin' : none of 2 overloads have a best conversion
f:\Work\prg\unnamed\include\0-utility\lang\foreach.h(281): could be 'foreach_detail::wrapper<boost::range_const_iterator<Range>::type> foreach_detail::begin(const Range &)'
f:\Work\prg\unnamed\include\0-utility\lang\foreach.h(274): or 'foreach_detail::wrapper<boost::range_iterator<Range>::type> foreach_detail::begin(Range &)'
while trying to match the argument list '(const std::list<_Ty,_Ax>)'
with
[
_Ty=Phoenix::PBoundedObject,
_Ax=std::allocator<Phoenix::PBoundedObject>
]


не может выбрать из этих двух вариантов:
template<class Range>
wrapper<typename boost::range_iterator<Range>::type>
    begin( Range& range )
{
    return boost::begin( range );
}

template<class Range>
wrapper<typename boost::range_const_iterator<Range>::type>
    begin(Range const& range )
{
    return boost::begin( range );
}


компилировал такое:
const list<PBoundedObject>& objects;
foreach (const PBoundedObject& i, objects)


Кстати я уже делал замечания по поводу этого foreach, но похоже не в этой ветке.
В твоей реализации эта ошибка тоже присутствует:

F>#define FOR_EACH( ElementDecl, Range )\
F>    if( bool _fe_break = false ) {}\
F>    else\
F>    for( foreach_detail::holder const\
F>              &_fe_current = foreach_detail::begin(Range)\
F>            , &_fe_last    = foreach_detail::end(Range)\

здесь нужно не
F> ; _fe_current(Range) != _fe_last(Range) && (_fe_break = !_fe_break)\
а
F> ; (_fe_break = !_fe_break) && _fe_current(Range) != _fe_last(Range)\

F>        ; ++_fe_current(Range)\
F>    )\
F>    for( ElementDecl = *_fe_current(Range); _fe_break; _fe_break = false )\
F>// end macro


а то на таком примере будет boom:

foreach (int& i, obj->ints) {
    obj=NULL;
    break;
}
... << RSDN@Home 1.1.3 stable >>
Re[8]: No more ugly functors
От: Костя Ещенко Россия  
Дата: 15.01.05 08:52
Оценка:
yxiie wrote:

> Ну что за беда у меня с этими foreach

> вариант WolfHound'a время от времени выдает run-time check failure — stack around 'xxx' variable corrupted,
> у меня подозрения, что он пропускает больше прогонов цикла, чем нужно, а твой вариант
> даже не компилится VC 7.0
>
>

> f:\...xxx.cpp(24) : error C2667: 'foreach_detail::begin' : none of 2 overloads have a best conversion
> f:\Work\prg\unnamed\include\0-utility\lang\foreach.h(281): could be 'foreach_detail::wrapper<boost::range_const_iterator<Range>::type> foreach_detail::begin(const Range &)'
> f:\Work\prg\unnamed\include\0-utility\lang\foreach.h(274): or 'foreach_detail::wrapper<boost::range_iterator<Range>::type> foreach_detail::begin(Range &)'
> while trying to match the argument list '(const std::list<_Ty,_Ax>)'
> with
> [
> _Ty=Phoenix::PBoundedObject,
> _Ax=std::allocator<Phoenix::PBoundedObject>
> ]

>
> не может выбрать из этих двух вариантов:
>
> template<class Range>
> wrapper<typename boost::range_iterator<Range>::type>
>     begin( Range& range )
> {
>     return boost::begin( range );
> }
> 
> template<class Range>
> wrapper<typename boost::range_const_iterator<Range>::type>
>     begin(Range const& range )
> {
>     return boost::begin( range );
> }
>

>
> компилировал такое:
>
> const list<PBoundedObject>& objects;
> foreach (const PBoundedObject& i, objects)
>


Ну это явно косяк 7.0, я когда писал ту реализацию и не расчитывал на совместимость с VC6/7.0.
А с вариантом WH надо разобраться — почему там stack corruption. Может оптимизатор чего не так наоптимизировал?
Как вариант лечения FOR_EACHевых проблем могу предложить попробовать BOOST_FOR_EACH от Eric Niebler, он развивается-сопровождается, последняя версия лежит здесь. Может заработает с VC7.0?

> Кстати я уже делал замечания по поводу этого foreach, но похоже не в этой ветке.

> В твоей реализации эта ошибка тоже присутствует:
>
>
> F>#define FOR_EACH( ElementDecl, Range )\
> F>    if( bool _fe_break = false ) {}\
> F>    else\
> F>    for( foreach_detail::holder const\
> F>              &_fe_current = foreach_detail::begin(Range)\
> F>            , &_fe_last    = foreach_detail::end(Range)\
>

> здесь нужно не
> F> ; _fe_current(Range) != _fe_last(Range) && (_fe_break = !_fe_break)\
> а
> F> ; (_fe_break = !_fe_break) && _fe_current(Range) != _fe_last(Range)\
>
>
> F>        ; ++_fe_current(Range)\
> F>    )\
> F>    for( ElementDecl = *_fe_current(Range); _fe_break; _fe_break = false )\
> F>// end macro
>

>
> а то на таком примере будет boom:
>
>
> foreach (int& i, obj->ints) {
> obj=NULL;
> break;
> }
>


Спасибо, помнится я видел такое замечание, но видимо забыл об этом когда писал последнюю версию.
Posted via RSDN NNTP Server 1.9
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[9]: No more ugly functors
От: Костя Ещенко Россия  
Дата: 15.01.05 09:16
Оценка:
Костя Ещенко wrote:

Сорри, BOOST_FOREACH здесь http://boost-sandbox.sourceforge.net/vault/index.php?directory=eric_niebler
Posted via RSDN NNTP Server 1.9
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[10]: No more ugly functors
От: yxiie Украина www.enkord.com
Дата: 15.01.05 10:51
Оценка:
Здравствуйте, Костя Ещенко, Вы писали:

КЕ>Костя Ещенко wrote:


КЕ>Сорри, BOOST_FOREACH здесь http://boost-sandbox.sourceforge.net/vault/index.php?directory=eric_niebler


точно также глючит

спотыкается на таком коде:

template <class T>
inline common_ptr<T> BNamespace::Find(const string& name) const {
    BOOST_FOREACH (PEntity i, this->contents)
    // BOOST_FOREACH (const PEntity& i, this->contents) глючит точно также
        if (i->GetName()==name) {
            if (i->GetType()==T::Type)
                return static_pointer_cast<T>(i);
            else
                return NULL;
        }

    return NULL;
}


я так понимаю это как-то связано с тем, что метод является const.
но почему тогда вариант WolfHound нормально компилился?
... << RSDN@Home 1.1.3 stable >>
Re[11]: No more ugly functors
От: Костя Ещенко Россия  
Дата: 15.01.05 14:29
Оценка:
yxiie wrote:

> КЕ>Сорри, BOOST_FOREACH здесь http://boost-sandbox.sourceforge.net/vault/index.php?directory=eric_niebler

>
> точно также глючит
>
> спотыкается на таком коде:
>
>
> template <class T>
> inline common_ptr<T> BNamespace::Find(const string& name) const {
> BOOST_FOREACH (PEntity i, this->contents)
> // BOOST_FOREACH (const PEntity& i, this->contents) глючит точно также
> if (i->GetName()==name) {
> if (i->GetType()==T::Type)
> return static_pointer_cast<T>(i);
> else
> return NULL;
> }
> 
> return NULL;
> }
>

>
> я так понимаю это как-то связано с тем, что метод является const.

Здесь http://boost-sandbox.sourceforge.net/libs/foreach/doc/html/boost_foreach/portability.html написано что VC7.0 имеет второй (нижний) уровень совместимости с BOOST_FOREACH, что означает что он не сможет работать с контейнером-rvalue. Но this->contents является const lvalue, так что все должно работать. Напиши в gmane.comp.lib.boost.user о баге, может починят.

> но почему тогда вариант WolfHound нормально компилился?


Тот который с container_traits или без них?
Posted via RSDN NNTP Server 1.9
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[12]: No more ugly functors
От: yxiie Украина www.enkord.com
Дата: 15.01.05 14:44
Оценка:
Здравствуйте, Костя Ещенко, Вы писали:

КЕ>Здесь http://boost-sandbox.sourceforge.net/libs/foreach/doc/html/boost_foreach/portability.html написано что VC7.0 имеет второй (нижний) уровень совместимости с BOOST_FOREACH, что означает что он не сможет работать с контейнером-rvalue. Но this->contents является const lvalue, так что все должно работать.


да, я читал...

КЕ>Напиши в gmane.comp.lib.boost.user о баге, может починят.


эээ... а как это?

>> но почему тогда вариант WolfHound нормально компилился?


КЕ>Тот который с container_traits или без них?


тот который без. семерка ведь не поддерживает частичную специализацию.
... << RSDN@Home 1.1.3 stable >>
Re[13]: No more ugly functors
От: Костя Ещенко Россия  
Дата: 16.01.05 03:08
Оценка:
yxiie:

> КЕ>Здесь http://boost-sandbox.sourceforge.net/libs/foreach/doc/html/boost_foreach/portability.html написано что VC7.0 имеет второй (нижний) уровень совместимости с BOOST_FOREACH, что означает что он не сможет работать с контейнером-rvalue. Но this->contents является const lvalue, так что все должно работать.

>
> да, я читал...
>
> КЕ>Напиши в gmane.comp.lib.boost.user о баге, может починят.
>
> эээ... а как это?

Вот полный урл группы news://news.gmane.org/gmane.comp.lib.boost.user , используешь любой news-клиент, например Outlook Express.

> >> но почему тогда вариант WolfHound нормально компилился?

>
> КЕ>Тот который с container_traits или без них?
>
> тот который без. семерка ведь не поддерживает частичную специализацию.

Этот вариант не пытается понять что за контейнер ему передали. Из-за этого ему плевать на константность, но он не может работать ни с чем кроме STL-like контейнеров.
Posted via RSDN NNTP Server 1.9
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[14]: No more ugly functors
От: yxiie Украина www.enkord.com
Дата: 20.01.05 12:49
Оценка:
я запостил в boost-users — ошибку компиляции он исправил. но после запуска у его варианта тоже выскаквает stack around variable 'xxx' corrupted. причем даже там, где вариант WolfHound'a работал
... << RSDN@Home 1.1.3 stable >>
Re[2]: No more ugly functors
От: yxiie Украина www.enkord.com
Дата: 20.01.05 15:32
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>1)Оптимизатор в VC++7.1 работает на отлично с ооочень маленьким минусом.

WH>2)Учитывая что
WH> а)Я уже и не помню когда мне был нужен break/continue
WH> б)А цикл с такой смешной нагрузкой я использовал еще раньше...
WH>Утверждаю к использованию в своих проектах.

ну и как? используешь ли?
хотелось бы услышать твои впечатления, а то у меня как раз один негатив.
... << RSDN@Home 1.1.3 stable >>
Re[3]: No more ugly functors
От: WolfHound  
Дата: 20.01.05 16:19
Оценка:
Здравствуйте, yxiie, Вы писали:

Y>ну и как? используешь ли?

Y>хотелось бы услышать твои впечатления, а то у меня как раз один негатив.
Было пару раз. Вроде работает. Просто я сейчас на C# пишу... а там практически одни foreach'и...
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[8]: No more ugly functors
От: WolfHound  
Дата: 20.01.05 16:19
Оценка:
Здравствуйте, yxiie, Вы писали:

Y>Ну что за беда у меня с этими foreach

Y>вариант WolfHound'a время от времени выдает run-time check failure — stack around 'xxx' variable corrupted,
Y>у меня подозрения, что он пропускает больше прогонов цикла, чем нужно, а твой вариант
Может дело в
Y>даже не компилится VC 7.0
Просто я тлько на 7.1 это пробовал.
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[4]: No more ugly functors
От: yxiie Украина www.enkord.com
Дата: 20.01.05 17:58
Оценка:
Здравствуйте, WolfHound, Вы писали:

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


Y>>ну и как? используешь ли?

Y>>хотелось бы услышать твои впечатления, а то у меня как раз один негатив.
WH>Было пару раз. Вроде работает. Просто я сейчас на C# пишу... а там практически одни foreach'и...

в том то и дело, что "вроде"
... << RSDN@Home 1.1.3 stable >>
Re[9]: No more ugly functors
От: yxiie Украина www.enkord.com
Дата: 20.01.05 17:58
Оценка:
Здравствуйте, WolfHound, Вы писали:

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


Y>>Ну что за беда у меня с этими foreach

Y>>вариант WolfHound'a время от времени выдает run-time check failure — stack around 'xxx' variable corrupted,
Y>>у меня подозрения, что он пропускает больше прогонов цикла, чем нужно, а твой вариант
WH>Может дело в
Y>>даже не компилится VC 7.0
WH>Просто я тлько на 7.1 это пробовал.

черт его знает, а чего в нем особенного такого?
кстати BOOST_FOREACH точно также глючит. даже больше
... << RSDN@Home 1.1.3 stable >>
Re[5]: No more ugly functors
От: WolfHound  
Дата: 20.01.05 18:18
Оценка:
Здравствуйте, yxiie, Вы писали:

Y>в том то и дело, что "вроде"

Ну я глюков не замечал.
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[10]: No more ugly functors
От: WolfHound  
Дата: 20.01.05 18:18
Оценка:
Здравствуйте, yxiie, Вы писали:

Y>черт его знает, а чего в нем особенного такого?

Старый.
Y>кстати BOOST_FOREACH точно также глючит. даже больше
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[6]: No more ugly functors
От: yxiie Украина www.enkord.com
Дата: 20.01.05 19:58
Оценка:
Здравствуйте, WolfHound, Вы писали:

Y>>в том то и дело, что "вроде"

WH>Ну я глюков не замечал.

good for you. можешь спать спокойно
а я сейчас собираюсь кучи кода переписывать с foreach на for
... << RSDN@Home 1.1.3 stable >>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.