Вот создал макрос для перебора всех элементов контейнера, стараясь как можно больше приблизиться к
приведенному там синтаксису.
В результате организация цикла выглядит примерно так: FOR_EACH(int& i, the_container)
#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_ и очень доволен.
Здравствуйте, Юнусов Булат, Вы писали:
ЮБ>Здравствуйте, folk, Вы писали:
ЮБ>Чем функторы то так не нравятся, рульно же когда цикл в одном месте а алгоритм в другом — нафига обртно все в кучу упихивать то?
Доказывать с пеной у рта не буду, но по-моему не рульно. Потому что расщепляет некую целостность на два фрагмента, далеко расположенных по тексту друг от друга.
Далее. Есть такой принцип : make simple things simple. Или по-русски: не надо для убиения одного комара кидать ядрёную бонбу.
Фактически, единственный профит от for_each, например, то что кишки упрятаны. Типа меньше ошибок и своего рода инкапсуляция получается.
Ну так придумайте инкапсуляцию для операторов как свойство языка. Это было бы, по-моему, куда более продуктивно. Вместо того, чтобы вкладывать колоссальные усилия в реализации на шаблонах. Там нужны усилия и здесь, только в одном случае результатом будет заточка инструмента под решение задач, а во втором -- притягивние задач за уши к инструменту. Т.е. в одном случае продуктивная взаимная любовь, а в другом -- изнасилование.
Поясню немного. Что есть выделенное жирным шрифтом. Оператор цикла, да? После него стоит тело, к которму он применяется.
Фактичкски, здесь стоит inline определение некоторой сущности. Что хочется. Это определение сделать outline. Скрыть детальки, оставив наруже только интерфейс -- входной и операторный. Тогда циклирование сведется к двум шагам: построение этого оператора и применение его к, между прочим, тоже некотрой inline определённой сущности. Ага? Алгоритм же for_each не решает задачи, он просто убирает с глаз долой сам цикл и ничего больше. Не, он ещё создаёт сложности в связывании с телом.
Создаём объект F. Засовываем его через аргумент. Зачем-то. Хотя всё что нужно для дела -- рабочая головка().
F>Вот создал макрос для перебора всех элементов контейнера, стараясь как можно больше приблизиться к F>приведенному там синтаксису. F>В результате организация цикла выглядит примерно так: FOR_EACH(int& i, the_container)
F>Определение макроса:
F>Вот создал макрос для перебора всех элементов контейнера, стараясь как можно больше приблизиться к F>приведенному там синтаксису. F>В результате организация цикла выглядит примерно так: FOR_EACH(int& i, the_container)
F>Определение макроса:
F>
Здравствуйте, Шахтер, Вы писали:
Ш>Доказывать с пеной у рта не буду, но по-моему не рульно. Потому что расщепляет некую целостность на два фрагмента, далеко расположенных по тексту друг от друга.
А нужна она эта целостность? Что лучше отлаживать сам-по-себе одинокий функтор или цикл посреди остального кода?
Ш>Далее. Есть такой принцип : make simple things simple. Или по-русски: не надо для убиения одного комара кидать ядрёную бонбу.
С каких это пор тривиальные вещи стали бомбой? Давай без эмоций и эротических фантазий — они тут неуместы.
Ты во что форич выливается в исходниках видел?
Ш>Фактически, единственный профит от for_each, например, то что кишки упрятаны. Типа меньше ошибок и своего рода инкапсуляция получается.
F>Вот создал макрос для перебора всех элементов контейнера, стараясь как можно больше приблизиться к F>приведенному там синтаксису. F>В результате организация цикла выглядит примерно так: FOR_EACH(int& i, the_container)
хъ
Красота (ну почти см ниже)
F>Вижу в этом решении следующие проблемы (не считая проблем идеологического характера):
Нет ни каких проблем есть фанатизм.
F>1. break работает точно так же, как continue, а хотелось бы полного соответствия семантике цикла.
fixed
F>2. Постоянные ненужные вызовы container.begin() и container.end(), служащие только для определения того, к какому типу надо приводить базовую ссылку. Но проверка asm-листинга VC6 для этого примера показала что все эти вызовы выкидывются оптимизатором. Для VC7.1 даже проверять не стал.
В асм иногода заглядывать надо
В первом варианте в место
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, ebxtest 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:
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) А. Эйнштейн
Здравствуйте, WolfHound, Вы писали:
WH>Здравствуйте, alexkro, Вы писали:
A>>А как тебе версия Niebler'а? (ftp://ftp.cuj.com/pub/2003/cujnov2003.zip). WH>И чем он лучше кроме того что там написано больше?
Для массивов работает, например. Да и, вообще, уважаемый человек написал.
Здравствуйте, alexkro, Вы писали:
A>>>А как тебе версия Niebler'а? (ftp://ftp.cuj.com/pub/2003/cujnov2003.zip). WH>>И чем он лучше кроме того что там написано больше? A>Для массивов работает, например.
Ну мой тоже.
А еще чем? A>Да и, вообще, уважаемый человек написал.
Не аргумент.
А вот чем его вариант хуже я могу сказать... Слабо скормить два итератора?
... << RSDN@Home 1.1 beta 2 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, WolfHound, Вы писали:
WH>Здравствуйте, alexkro, Вы писали:
A>>>>А как тебе версия Niebler'а? (ftp://ftp.cuj.com/pub/2003/cujnov2003.zip). WH>>>И чем он лучше кроме того что там написано больше? A>>Для массивов работает, например. WH>Ну мой тоже. WH>А еще чем?
Ok, все беру, и твое решение с break, и стилевые изменения. Только имена макросов все же оставлю заглавными буквами.
Правда я еще не смотрел ссылки от alexkro, сейчас этим и займусь.
А специализации для массивов я не стал создавать потому что у меня на работе используется VC6, соответственно код должен быть VC6-совместимым. Так что для меня лямбда как правило недоступна и утверждение "No more ugly functors (and explicit cycles)" очень актуально.
Здравствуйте, Юнусов Булат, Вы писали:
ЮБ>Впрочем Мейерс лучше сказал http://www.cuj.com/documents/s=8191/cuj0110smeyers/
ЮБ>Кроме того алгоритмы меж собой хорошо сочетаются, вкладываются итп.
ЮБ>Твою задачу тоже можно в функтор посадить, поставить еще бы проверок на все что можно и дальше пользоватся. ЮБ>
Я попрошу не обижаться, но не считаю возможным с вами дискутировать. А то мне придётся нарушить правила форума. Я надеюсь, что вы сами прочтёте свой код ещё раз и поймёте, что не правы.
Что касается господина Мейерса, то статью эту я читал. Мне она не понравилась. Автор явно не профессионал в программировании. Я так понимаю, он алгоритмист.
Смысл этой статьи -- в промоушене своих услуг. Такие вещи надо понимать, это Запад, всё-таки.
P.S.
Знаете, как отличить хорошего программиста от посредственного? По способности не делать мелких ляпов.
Так, профессиональный пианист не ошибается в гаммах, например.
И даю совет напоследок. Если постите код, даже иллюстративный, постарайтесь написать его чисто и аккуратно (и, естественно, правильно).
Не стоит ходить в оперу в заплатанных джинсах -- это неприлично.
[]
A>Классная штука ! A>Не мог бы ты пояснить как работает макрос FOR_EACH_ ? А то не совсем понятно применение врапперов и вложенных циклов.
Сначала про врапперы.
Мы не хотим явно передавать тип контейнера в одном из аргументов макроса, так никакого попса не будет. В то же время для организации цикла нам нужно объявить два итератора — текущий и маркер окончания цикла.
Т.е. проблема в том что без оператора typeof мы никак не можем узнать какой тип итераторов указывать в объявлении.
Решение такое — с помощью функции wrap создаем 2 временных значения — обертки над итераторами и определяем 2 ссылки на базовый класс оберток (их тип известен). Эти обертки будут жить пока живут эти ссылки (thanx 2 jazzer).
Каждый раз когда нам нужно обратиться к итератору мы кастим ссылку на базу к ссыкле на обертку, а от обертки получаем итератор.
Про вложенные циклы.
Первый цикл нужен собственно для организации итерирования по контейнеру.
Второй цикл возвращает управление первому после одной итерации. Он служит только для объявления временного объекта и присвоения ему значения на которое указывает итератор.
Здравствуйте, 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>}
Если бы он вошел в поставку boost, то вполне возможно стал бы им пользоваться. Но, насколько я понял, этого не будет, несмотря на некоторые положительные отзывы, такое решение не приглянулось ценителям камерного искусства
Здравствуйте, Шахтер, Вы писали:
Ш>Я попрошу не обижаться, но не считаю возможным с вами дискутировать. А то мне придётся нарушить правила форума. Я надеюсь, что вы сами прочтёте свой код ещё раз и поймёте, что не правы.
Беседер, я тоже не горю желаньем, но было бы сначала неплохо узнать где я неправ, если это так, конечно, а хаяние чужого кода никогда никого не красило.
Ш>Что касается господина Мейерса, то статью эту я читал. Мне она не понравилась. Автор явно не профессионал в программировании. Я так понимаю, он алгоритмист. Ш>Смысл этой статьи -- в промоушене своих услуг. Такие вещи надо понимать, это Запад, всё-таки.
Что надо понять? Что Мейерс как бы сказать помягче — популист? Использование stl — это низкопоклонство перез западом? STL Степанов изобрел вообще-то — тоже ради промоушена?
Впрочем, оставим Мейерса, ему не жарко ни холодно от ваших оценок.
Ш>P.S. Ш>Знаете, как отличить хорошего программиста от посредственного? По способности не делать мелких ляпов. Ш>Так, профессиональный пианист не ошибается в гаммах, например. Ш>И даю совет напоследок. Если постите код, даже иллюстративный, постарайтесь написать его чисто и аккуратно (и, естественно, правильно). Ш>Не стоит ходить в оперу в заплатанных джинсах -- это неприлично.
Я не Мейерс, но повертье, меня это тоже не задевает.
Здравствуйте, Шахтер, Вы писали:
Ш> Я попрошу не обижаться, но не считаю возможным с вами дискутировать. Ш> А то мне придётся нарушить правила форума. Я надеюсь, что вы сами Ш> прочтёте свой код ещё раз и поймёте, что не правы. <...> Ш> 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
Оценка:
Здравствуйте, Юнусов Булат, Вы писали:
ЮБ> но было бы сначала неплохо узнать где я неправ,
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 тоже проблема, поскольку см. выше.
Здравствуйте, MaximE, Вы писали:
ME>Здравствуйте, Шахтер, Вы писали:
ME>[]
Ш>>Ну так придумайте инкапсуляцию для операторов как свойство языка. Это было бы, по-моему, куда более продуктивно.
ME>Все уже придумано: boost::lambda.
ME>Слышал, что предлагают добавить лямбда-выражения в core language.
Вот если в core language, то это в coreне меняет дело.
Здравствуйте, Шахтер, Вы писали:
Ш>Здравствуйте, Юнусов Булат, Вы писали:
ЮБ>>Здравствуйте, Аноним, Вы писали:
А>>>Булат, Вы промахнулись в этой строчке: А>>>
Здравствуйте, Шахтер, Вы писали:
Ш> 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"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>Здравствуйте, Шахтер, Вы писали:
Ш>> 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.
( Напомню свою сигнатуру: #define FOR_EACH_(Decl, First, Last) )
Я тоже думал над подобным вариантом. Но на всякий случай решил не _использовать_ результат аргумента Last на каждой итерации. Это мне показалось более безопасным. Также я допускал что это облегчит жизнь оптимайзеру.
Опосля пришла мысль что лучше кастить к First, чем к Last, т.к. у тех реализаций контейнеров, что я видел, метод begin() устроен либо проще чем end(), либо они примерно одинаковы.
F>Я тоже думал над подобным вариантом. Но на всякий случай решил не _использовать_ результат аргумента Last на каждой итерации. Это мне показалось более безопасным. Также я допускал что это облегчит жизнь оптимайзеру.
F>Опосля пришла мысль что лучше кастить к First, чем к Last, т.к. у тех реализаций контейнеров, что я видел, метод begin() устроен либо проще чем end(), либо они примерно одинаковы.
Ну я наоборот считаю end() более простой операцией — так как это же fake'овый объект как правило и его проще построить.
Здравствуйте, lboss, Вы писали:
L>Здравствуйте, folk, Вы писали:
F>>Я тоже думал над подобным вариантом. Но на всякий случай решил не _использовать_ результат аргумента Last на каждой итерации. Это мне показалось более безопасным. Также я допускал что это облегчит жизнь оптимайзеру.
F>>Опосля пришла мысль что лучше кастить к First, чем к Last, т.к. у тех реализаций контейнеров, что я видел, метод begin() устроен либо проще чем end(), либо они примерно одинаковы.
L>Ну я наоборот считаю end() более простой операцией — так как это же fake'овый объект как правило и его проще построить.
И на это есть ответ
Я рассматривал подобный монолитный вариант, но мне подумалось что я смогу повторно использовать элементарные wrap/unwrap для другой задачи, так что в результате сделал на них и поместил их в namespace util (а не в _foreach как в опубликованном варианте).
А вообще это правильно, чем больше удается вынести из мароса в шаблон, тем лучше. В скопе цикла находятся меньше скрытых макросом переменных.
Здравствуйте, Шахтер, Вы писали:
Ш>>> <... цитата из 5/4 ...>
Ш>>> стандарт относит это к unspecified behavior
ПК>> Хуже: undefined.
Ш> В таком случае попрошу поподробнее. Ш> Почему в коментария написано unspecified (опечатка?).
Да, опечатка, даже defect report имеется: http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/cwg_active.html#351
Ш> В чем разница между unspecified и undefined. Только не надо отсылать Ш> к стандарту. У старенького дяди Шахтёра мозгА в этом стандарте не всё Ш> понимает.
ЮБ>>Чем функторы то так не нравятся, рульно же когда цикл в одном месте а алгоритм в другом — нафига обртно все в кучу упихивать то?
Ш>Доказывать с пеной у рта не буду, но по-моему не рульно. Потому что расщепляет некую целостность на два фрагмента, далеко расположенных по тексту друг от друга.
зато использование таких супер макросов как у тебя чрезвычайно рульно..
Веру-ю-у! В авиацию, в научную революци-ю-у, в механизацию сельского хозяйства, в космос и невесомость! Веру-ю-у! Ибо это объективно-о! (Шукшин)
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?
Здравствуйте, folk, Вы писали:
F>И на это есть ответ F>Я рассматривал подобный монолитный вариант, но мне подумалось что я смогу повторно использовать элементарные wrap/unwrap для другой задачи, так что в результате сделал на них и поместил их в namespace util (а не в _foreach как в опубликованном варианте).
Не понял аргументации — ибо для практически любой другой задачи проще итераторами пользоваться всё-таки... по моему...
F>А вообще это правильно, чем больше удается вынести из мароса в шаблон, тем лучше. В скопе цикла находятся меньше скрытых макросом переменных.
Вообще-то, по моему, главный принцип (или заслуга) данного подхода — это работающий break, и ясность реализации...
Здравствуйте, MaximE, Вы писали:
ME>Такие конструкции и не должны работать.
ME>Это мелкософтовские студии такое позволяют. Если отключить "language extensions" в семерке, то такую ерунду уже не получится написать.
Ну ладно — это в конечном случае не принципиально. С моей точки зрения тут всё нормально ибо "const" это просто модификатор — сути он не меняет. Я считаю что запись:
Здравствуйте, folk, Вы писали:
F>Не уверен что правильно понял. Наше rvalue класс-типа может быть неявно преобразовано в lvalue?
Однако ты прав.
То бишь не может.
То бишь код неправильный
А товарищи cl 7.1 и icl 7.1 тоже неправы, а g++ рулит
Таки rvalue может инициализировать только константную ссылку.
А объект возвращаемый функцией by value является rvalue.
Но! От него позволяется вызвать метод.
А если этот метод вернёт ссылку на него самого, то ею можно будет инициализировать
неконстантную ссылку
EX>Но! От него позволяется вызвать метод. EX>А если этот метод вернёт ссылку на него самого, то ею можно будет инициализировать EX>неконстантную ссылку
Не, нельзя так делать, темпоральный объект помрёт
Ш> В этом коде насколько оправдан вызов 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 делать не должны
Т.е. изменять свое внутреннее состояние они не могут?
Здравствуйте, , Вы писали:
Ш>>> Requires: op and binary_op shall not have any side effects. Ш>>> Что эта фраза означает?
ПК>> <...>
> Т.е. изменять свое внутреннее состояние они не могут?
Не могут. Например, гарантий, что функтор не будет копироваться, нет. В этом аспекте приведенный код формально неверен. Правда, сомневаюсь,
что на практике хотя бы одна реализация стандартной библиотеки не будет
работать с данным функтором.
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
ПК>Не могут. Например, гарантий, что функтор не будет копироваться, нет. ПК>В этом аспекте приведенный код формально неверен. Правда, сомневаюсь, ПК>что на практике хотя бы одна реализация стандартной библиотеки не будет ПК>работать с данным функтором.
Да, для правильности (тот же Мейерс Effective STL), надо было конструктор копирования приписать, поленился, там еще и проверок нет скажем на нульность агрумента конструктора и на выход за границы массива.
Здравствуйте, Юнусов, Вы писали:
ПК>> Не могут. Например, гарантий, что функтор не будет копироваться, нет.
ЮБ> Да, для правильности (тот же Мейерс Effective STL), надо было конструктор ЮБ> копирования приписать
А как бы он помог в данном случае, если бы для одной части диапазона
использовалась одна копия, а для другой — другая?
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>А как бы он помог в данном случае, если бы для одной части диапазона ПК>использовалась одна копия, а для другой — другая?
Здравствуйте, Юнусов, Вы писали:
ПК>> А как бы он помог в данном случае, если бы для одной части диапазона ПК>> использовалась одна копия, а для другой — другая?
ЮБ> А как такое может случится?
Я тоже очень сомневаюсь в практической осуществимости подобного, но формально
ничто в стандарте не запрещает реализации сделать такую гадость Собственно,
я полагаю, что авторы стандарта, решив не тратить усилия на формулировки того,
какие именно побочные эффекты запрещены, на всякий случай перестраховались,
добавив требование отсутствия любых.
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, Павел, Вы писали:
ПК> Собственно, я полагаю, что авторы стандарта, решив не тратить усилия ПК> на формулировки того, какие именно побочные эффекты запрещены, ПК> на всякий случай перестраховались, добавив требование отсутствия любых.
Ага... Дальнейшее разбирательство показало, что имеется 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"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
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]
ПК>Соответственно, наши нынешние практические ожидания подтверждаются дальнейшими ПК>изысканиями формалистов-стандартизаторов
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]
ЮБ>значит выделенный код будет считатся неверным ЮБ>
С этим кодом и было, и будет все в порядке: конструирование функтора никак не взаимодействует с дальнейшим выполнением std::transform. В процитированном фрагменте речь шла о побочных эффектах внутри operator(). В текущей редакции стандарта запрещены любые побочные эффекты, в том числе и модификация данных-членов функтора. Предложенное исправление, вошедшее в текущий черновик, данное — имхо, чисто теоретическое — ограничение снимает.
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, lboss, Вы писали:
L>Здравствуйте, folk, Вы писали:
F>>И на это есть ответ F>>Я рассматривал подобный монолитный вариант, но мне подумалось что я смогу повторно использовать элементарные wrap/unwrap для другой задачи, так что в результате сделал на них и поместил их в namespace util (а не в _foreach как в опубликованном варианте).
L>Не понял аргументации — ибо для практически любой другой задачи проще итераторами пользоваться всё-таки... по моему...
Тоже не понял... Что есть практически любая задача? Я совершенно не имел ввиду итераторы/контейнеры...
F>>А вообще это правильно, чем больше удается вынести из мароса в шаблон, тем лучше. В скопе цикла находятся меньше скрытых макросом переменных.
L>Вообще-то, по моему, главный принцип (или заслуга) данного подхода — это работающий break, и ясность реализации...
Ну с break то все давно решено. А насчет ясности ты наверное прав.
Здравствуйте, Павел Кузнецов, Вы писали:
Ш>> В этом коде насколько оправдан вызов 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). Или ещё как-то. В данном же конкретно случае этот порядок принципиально важен -- иначе не будет работать. Замечание, приведённое выше, не по существу, т.к. оно верно, если нет связи между последовательностью операций, в нашем же случае такая связь есть. У нас же вычисление рекурсивной последовательности.
Между прочим, не так уж сложно написать библиотечку извращённых реализаций алгоритмов. Она может оказать неоценимую помощь при ловле вот таких тонких ситуаций.
Здравствуйте, Шахтер, Вы писали:
ПК>> Это определяется требованиями к алгоритму поддерживать работу с InputIterator. ПК>> Работа с InputIterator автоматически означает движение от начала к концу.
Ш> Здесь не всё так просто. И вот почему. Реализация библиотеки может Ш> предоставлять специализации алгоритма для различных типов функторов.
Теоретически — возможно. Практически — не представляю, зачем нужна специализация
std::transform, скажем, для random access iterators. Разве что специально для того,
чтобы "навернуть" функционал Юнуса Булатова Формально, ты, конечно, прав.
Ш> Стандарт, насколько я понимаю, всё-таки не определяет точно порядок выполнения Ш> преобразований. Он определяет только что будет аргументом, и куда кладутся Ш> результаты преобразований.
Даже конкретно по поводу порядка в 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"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
F>Вот создал макрос для перебора всех элементов контейнера, стараясь как можно больше приблизиться к F>приведенному там синтаксису. F>В результате организация цикла выглядит примерно так: FOR_EACH(int& i, the_container)
А можно ли данный FOR_EACH с std::map использовать ?
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, folk, Вы писали:
F>>#define FOR_EACH_(Decl, First, Last) \ F>>if (false) {} else /*VC6 for-init-scope bug workaround*/ \
А>А что это за баг такой и зачем здесь его надо обходить ?
баг в том, что в for(int i;); i видна после цикла, а по Стандарту она должна быть видна только внутри цикла
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 видна после цикла, а по Стандарту она должна быть видна только внутри цикла
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, 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.
F>>Вот создал макрос для перебора всех элементов контейнера, стараясь как можно больше приблизиться к F>>приведенному там синтаксису. F>>В результате организация цикла выглядит примерно так: FOR_EACH(int& i, the_container)
А>А можно ли данный FOR_EACH с std::map использовать ?
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, Аноним, Вы писали:
А>>Здравствуйте, folk, Вы писали:
F>>>Навеяно словами WolfHound'a в ветке C++/CLI PDC presentation
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. Например:
А>>FOR_EACH( pair<string,string>& i, mapStoS )
А>>
F>Проблема: препроцессор понимает запятую между string и string как разделитель аргументов макроса и ругается что макрос FOR_EACH не берет 3 аргумента. F>Интересно что я до сих пор не сталкивался с такой проблемой, т.к. всегда пользуюсь value_type. Например:
F>
Я считаю, что явно указывать тип переменной в заголовке цикла — лучше т.к. нагляднее демонстрирует по элементам какого типа будем проводить итерации ( контейнер может быть объявлен очень далеко от цикла ).
_>>PS. Жалко что макросы нельзя перегружать — тогда можно было бы не выдумывать новое имя FOR_EACH_M
dad>мне кажется что такой код не только не красивый, но и неправильный..
_>>>PS. Жалко что макросы нельзя перегружать — тогда можно было бы не выдумывать новое имя FOR_EACH_M
dad>>мне кажется что такой код не только не красивый, но и неправильный..
_>В чем неправильность ?
макросы надо рассматривать не как часть языка, а как часть компилятора, имхо,
использование их для сокрытия больших объемов кода, имхо — ламерство,
майкорсов ввело практику карт сообщений, что тоже не есть хорошо, но используется , закрыв глаза.
в этом же случае вообще просматривается попытка использовать макрос как конструкцию языка на подобие функции. что в корне не правильно даже для макроса!
если такая уж нужна — напиши функцию и используй ее зачем макрос то?и потом — такая беда практически не поддается отладке.
Веру-ю-у! В авиацию, в научную революци-ю-у, в механизацию сельского хозяйства, в космос и невесомость! Веру-ю-у! Ибо это объективно-о! (Шукшин)
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?
Думаю за это время многие уже успели его хорошо обкатать и использовать в деле. Какие отзывы?
Здравствуйте, 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) А. Эйнштейн
Здравствуйте, 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++ поддерживает частичную специализацию?
> А как с частичной специализацией и других компиляторов на других платформах?
Все новые версии основных компиляторов C++ на большинстве популярных платформ поддерживают частичную специализацию.
> Кстати, с какой версии _MSC_VER VC++ поддерживает частичную специализацию?
7.1
Posted via RSDN NNTP Server 1.9 alpha
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, 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().
Здравствуйте, 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
Работа над ошибками.
Было задумано так, что в аргумент Range макроса можно передавать std::make_pair(ptr,ptr). Тут есть проблема — результат make_pair является rvalue, а значит по стандарту не может приниматься функцией по неконстантной ссылке. Предыдущая версия этим не озаботилась, т.к. VC запросто принимает rvalue по неконстантной ссылке.
Исправлено, теперь каждая функция перегружена для константной ссылки.
F>Вот создал макрос для перебора всех элементов контейнера, стараясь как можно больше приблизиться к F>приведенному там синтаксису. F>В результате организация цикла выглядит примерно так: FOR_EACH(int& i, the_container)
F>Несмотря на все это я уже второй день пользую FOR_EACH и FOR_EACH_ и очень доволен.
дело вкуса, я юзаю STL и BOOST мне хватает.
советую глянуть лямбда-вычисления, некая замена безымянных функторов:
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));
Здравствуйте, Аноним, Вы писали:
А>дело вкуса, я юзаю STL и BOOST мне хватает. А>советую глянуть лямбда-вычисления, некая замена безымянных функторов
[]
std::for_each + boost::lambda, std::for_each + явный функтор, явный цикл, FOR_EACH — можно использовать что угодно, лишь бы было удобно и не было войны.
Здравствуйте, 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 в ассемблерном листинге без оверхеда.
Здравствуйте, 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 — единственная подходящая конструкция для объявления курсора.
Здравствуйте, 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) {}
но она не допустима
Здравствуйте, vdimas, Вы писали:
V>все ясно, тут не возразишь... V>но мне чисто внутренне приятней иметь 3 ассемблерные инструкции для организации цикла, вместо 6-ти (при использовании break)
Ага, не очень приятно это осозновать, но имхо break используется раз в пятилетку.
V>свой вариант я уже оформил и именно в том виде, как показал выше — с предварительным объявлением. V>Ok, беру ваш вариант, и называю его foreach_ref для тех случаев, где потребуется ссылка. (просто у меня чаще всего в коллекциях указатели хранятся, или их браться smart_ptr<они же>, т.е. я про ссылки не учел)
На всякий случай замечу, что создание копии умного указателя скорее всего обойдется дороже, чем принять его по константной ссылке и (если используется break) потратить вхолостую эти три инструкции.
Здравствуйте, folk, Вы писали:
F>Здравствуйте, vdimas, Вы писали:
V>>все ясно, тут не возразишь... V>>но мне чисто внутренне приятней иметь 3 ассемблерные инструкции для организации цикла, вместо 6-ти (при использовании break)
F>Ага, не очень приятно это осозновать, но имхо break используется раз в пятилетку.
я поражаюсь люди, откуда такие сведения???
я, например, заметил за собой довольной частое использование. откуда статистика?
yxiie:
> F>Ага, не очень приятно это осозновать, но имхо break используется раз в пятилетку. > > я поражаюсь люди, откуда такие сведения??? > я, например, заметил за собой довольной частое использование. откуда статистика?
это была метафора, художественное преувеличение
Сейчас поискал по текущему проекту, нашел 192 looping statement и 77 break, из них 66 находятся внутри switch. Получаем 192/11, т.е. 1 break на 17.(45) циклов.
Понятно что эти цифры ни о чем кроме этого самого проекта не говорят. Просто самому интересно стало.
Здравствуйте, folk, Вы писали:
F>На всякий случай замечу, что создание копии умного указателя скорее всего обойдется дороже, чем принять его по константной ссылке и (если используется break) потратить вхолостую эти три инструкции.
На всякий случай замечу, что пройтись по коллекции с умными указателями всегда удавалось обычным указателем
break я слишком часто юзаю, почти в 1/3 случаев. с ним алгоритмы самые короткие.
vdimas:
> F>На всякий случай замечу, что создание копии умного указателя скорее всего обойдется дороже, чем принять его по константной ссылке и (если используется break) потратить вхолостую эти три инструкции. > > На всякий случай замечу, что пройтись по коллекции с умными указателями всегда удавалось обычным указателем
Зависит от указателей, которые используешь. Бустовые умные не приводимы к "глупому" указателю, надо использовать get(). Так что с ними в FOR_EACH придется создавать копию.
> break я слишком часто юзаю, почти в 1/3 случаев. с ним алгоритмы самые короткие.
Ну что за беда у меня с этими 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, но похоже не в этой ветке.
В твоей реализации эта ошибка тоже присутствует:
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>
> ]
Ну это явно косяк 7.0, я когда писал ту реализацию и не расчитывал на совместимость с VC6/7.0.
А с вариантом WH надо разобраться — почему там stack corruption. Может оптимизатор чего не так наоптимизировал?
Как вариант лечения FOR_EACHевых проблем могу предложить попробовать BOOST_FOR_EACH от Eric Niebler, он развивается-сопровождается, последняя версия лежит здесь. Может заработает с VC7.0?
> Кстати я уже делал замечания по поводу этого foreach, но похоже не в этой ветке. > В твоей реализации эта ошибка тоже присутствует: > >
> 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 нормально компилился?
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 контейнеров.
я запостил в boost-users — ошибку компиляции он исправил. но после запуска у его варианта тоже выскаквает stack around variable 'xxx' corrupted. причем даже там, где вариант WolfHound'a работал
Здравствуйте, WolfHound, Вы писали:
WH>1)Оптимизатор в VC++7.1 работает на отлично с ооочень маленьким минусом. WH>2)Учитывая что WH> а)Я уже и не помню когда мне был нужен break/continue WH> б)А цикл с такой смешной нагрузкой я использовал еще раньше... WH>Утверждаю к использованию в своих проектах.
ну и как? используешь ли?
хотелось бы услышать твои впечатления, а то у меня как раз один негатив.
Здравствуйте, yxiie, Вы писали:
Y>ну и как? используешь ли? Y>хотелось бы услышать твои впечатления, а то у меня как раз один негатив.
Было пару раз. Вроде работает. Просто я сейчас на C# пишу... а там практически одни foreach'и...
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, 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) А. Эйнштейн
Здравствуйте, WolfHound, Вы писали:
WH>Здравствуйте, yxiie, Вы писали:
Y>>ну и как? используешь ли? Y>>хотелось бы услышать твои впечатления, а то у меня как раз один негатив. WH>Было пару раз. Вроде работает. Просто я сейчас на C# пишу... а там практически одни foreach'и...
Здравствуйте, 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 точно также глючит. даже больше