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 в ассемблерном листинге без оверхеда.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.