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


Автор: vinter 6.6.2008, 14:46
привет всем,
сегодня увидел такой код
Код

while(*src) *dest=*src, ++src, ++dest;

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

Автор: Peter 6.6.2008, 15:48
Цитата(vinter @  6.6.2008,  14:46 Найти цитируемый пост)
нафига это сделано?

С этим вопросом - к разработчикам стандарта Си++.

Цитата(vinter @  6.6.2008,  14:46 Найти цитируемый пост)
зачем тогда нужны ; , если почти все заменяют запятые в том числе и тело цикла?

Точка с запятой указывает конец оператора. А запятые объединяют выражения в один оператор. Того же самого эффекта можно было бы достичь, если написать
Код
while(*src) {*dest=*src; ++src; ++dest;}

Автор: Любитель 6.6.2008, 16:05
Запятые нужны в си, в первую очередь для форов (ну, не то, чтоб нужны - но удобно). В С++ - это, во-первых, наследие. Но кроме того есть перегрузка операторов, потому находятся и другие применения. Например, boost::asign.

Автор: JackYF 7.6.2008, 00:33
Запятые также иногда удобны в условиях конструкций if и while.

Автор: chipset 7.6.2008, 21:24
А ещё запятые можно перегружать  smile 

Автор: bronislav 8.6.2008, 21:30
Цитата(chipset @  7.6.2008,  20:24 Найти цитируемый пост)
А ещё запятые можно перегружать 

Специально для этого их и придумали  smile 

Автор: Alek86 9.6.2008, 09:40
Цитата(JackYF @  7.6.2008,  00:33 Найти цитируемый пост)
Запятые также иногда удобны в условиях конструкций if и while.

можно пример, когда они удобны?
ато я так сразу представить не могу

Автор: Fazil6 9.6.2008, 10:57
Цитата(bronislav @  8.6.2008,  21:30 Найти цитируемый пост)
Специально для этого их и придумали

совсем не для этого. Семантика оператора "," меняется при перегрузке и поэтому не рекомендуется его перегружать. Тудаже относится и перегрузка && и ||

Автор: Lazin 9.6.2008, 11:21
да вроде-бы можно перегружать, но только для своих классов...

Автор: Fazil6 9.6.2008, 11:51
Цитата(Lazin @  9.6.2008,  11:21 Найти цитируемый пост)
да вроде-бы можно перегружать, но только для своих классов... 

перегружать можно, но поведение его будет очень сильно отличаться. Реализовать его семантику при перегрузке невозможно, поэтому результат этого перегруженного оператора будет очень удивительным для пользователя класса. 
Вы ведь не будете перегружать "+" так чтобы он в итоге реализовывал "-"...

Добавлено через 9 минут и 15 секунд
вот подобный случай обсуждался
Цитата

http://forum.vingrad.ru/forum/topic-163376.html#st_0_view_0

Автор: Любитель 9.6.2008, 12:42
Fazil6, семантику менять - это нормально. Иногда Пример я уже привёл (boost::assign).

Автор: JackYF 9.6.2008, 17:18
Цитата(Alek86 @  9.6.2008,  08:40 Найти цитируемый пост)
можно пример, когда они удобны?
ато я так сразу представить не могу

Код

std::vector<std::string> buffers;
std::string s;
while (std::getline(std::cin, s), !std::cin.eof())
{
  buffers.push_back(s);
}

Автор: MAKCim 9.6.2008, 17:39
Цитата(Fazil6 @  9.6.2008,  11:51 Найти цитируемый пост)
Реализовать его семантику при перегрузке невозможно

почему?

Автор: Alek86 9.6.2008, 18:01
JackYF, конечно спорно
ради одной строчки так (имхо) загрязнять читаемость
наверное, к этом нужно привыкнуть..........

Автор: Fazil6 9.6.2008, 18:01
Цитата(MAKCim @  9.6.2008,  17:39 Найти цитируемый пост)
почему? 

потому, что нужно обеспечить порядок вычисления операндов

Автор: MAKCim 9.6.2008, 18:20
Цитата(Fazil6 @  9.6.2008,  18:01 Найти цитируемый пост)
потому, что нужно обеспечить порядок вычисления операндов 

и в чем проблема?
приведи пример, что по-твоему невозможно сделать

Автор: d06osipov 9.6.2008, 19:09
Цитата(Fazil6 @  9.6.2008,  10:57 Найти цитируемый пост)
Семантика оператора "," меняется при перегрузке и поэтому не рекомендуется его перегружать. Тудаже относится и перегрузка && и || 


Во-первых, я что-то не слышал про стандартную семантику && и ||. А во-вторых, при перегрузке копирующего конструктора и оператора = тоже меняется семантика. Это значит, их не рекомендуется перегружать?

Автор: Fazil6 9.6.2008, 20:26
Цитата(MAKCim @  9.6.2008,  18:20 Найти цитируемый пост)
приведи пример, что по-твоему невозможно сделать

не совсем понимаю вопроса. В свою очередь встречный вопрос: как обеспечить чтобы левый операнд вычислялся всегда первым, а правый вторым?
Цитата(d06osipov @  9.6.2008,  19:09 Найти цитируемый пост)
Во-первых, я что-то не слышал про стандартную семантику && и ||.

ну и чем ты гордишься? Почитай топик по ссылке - там четко видно к чему приводит перегрузка ||
Цитата(d06osipov @  9.6.2008,  19:09 Найти цитируемый пост)
А во-вторых, при перегрузке копирующего конструктора и оператора = тоже меняется семантика. Это значит, их не рекомендуется перегружать?

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

Автор: andrew_121 9.6.2008, 20:58
Цитата

После этого в лучшем случае ты будешь проклят своими колегами, а может и покалечат (оторвут руки)

Интересная дискуссия. Много нового узнал...
Но правда, не вижу надобности перегружать "operator ,".

Автор: bsa 9.6.2008, 21:14
andrew_121, действительно, надобности это делать почти никогда нет. Но, иногда встречаются случаи, когда сделав это мы получим что-то, например, удобочитаемость кода. Пример, что лучше выглядит, это:
Код
std::vector<int> array;
array.push_back(1);
array.push_back(2);
array.push_back(3);
array.push_back(4);
array.push_back(5);
array.push_back(6);
array.push_back(7);
или это
Код
std::vector<int> array;
using namespace boost::assign;
array += 1,2,3,4,5,6,7;

Автор: andrew_121 9.6.2008, 21:20
bsa: Да, беспорно, красивей, удобней, понятней! Респект!
Слышал про Boost, но некогда не юзал, поделитесь ссылками на оного. И на доки, и на форум об оном тожА. Плиз.

Автор: bsa 9.6.2008, 21:38
Цитата(andrew_121 @ 9.6.2008,  21:20)
Слышал про Boost, но некогда не юзал, поделитесь ссылками на оного.

http://www.google.com/search?q=boost

Добавлено через 2 минуты и 6 секунд
Цитата(MAKCim @ 9.6.2008,  18:20)
Цитата(Fazil6 @  9.6.2008,  18:01 Найти цитируемый пост)
потому, что нужно обеспечить порядок вычисления операндов 

и в чем проблема?
приведи пример, что по-твоему невозможно сделать

Вся хитрость операторов && и || в том, что они не вычисляют второй свой аргумент, если уже по первому известен результат.

Автор: skyboy 9.6.2008, 21:51
почитайте про http://alenacpp.blogspot.com/2005/11/sequence-points.html
undefined behavior не страшен только тем, кто "намертво" прикреплен к одной версии определенного компилятора. В противном случае, может оказаться, что программа работает не так, как надо. Только потому,  что кто-то ради "удобочитаемости"(и то - спорно) вместо пяти точек следования(к примеру; т.е. 5 строк с ";" в конце) сделал одну(после выражения перед первой запятой в строке). 

Автор: andrew_121 9.6.2008, 22:43
skyboy:  То же вариант.

Автор: d06osipov 10.6.2008, 09:03
Цитата(Fazil6 @  9.6.2008,  20:26 Найти цитируемый пост)
в четырнадцатых слабо себе представляю перегрузку копирующего конструктора, с изменяющейся семантикой

А что, есть смысл перегружать что-либо без изменения семантики? 


Цитата(Fazil6 @  9.6.2008,  20:26 Найти цитируемый пост)
Цитата(d06osipov @  9.6.2008,  19:09 Найти цитируемый пост)
Во-первых, я что-то не слышал про стандартную семантику && и ||.

ну и чем ты гордишься? Почитай топик по ссылке - там четко видно к чему приводит перегрузка ||

Перегрузка && и ||, как и перегрузка любых других операторов, приводит к изменению их семантики (вполне возможно, предыдущая семантика --- ошибка компиляци). Есть одна стандартная версия &&, || и т. п. для параметров (bool,bool) которую можно применять к указателям используя конвертацию указателей к bool. Что же может испортить перегрузка этих операторов для объектов и ссылок на объекты? Даже для указателей, мне кажется, гораздо опаснее использовать неявную конвертацию к bool, чем перегружать для них оператор && (тем более, что для (bool,bool) его нельзя перегрузить).

Автор: Fazil6 10.6.2008, 09:58
Цитата(d06osipov @  10.6.2008,  09:03 Найти цитируемый пост)
А что, есть смысл перегружать что-либо без изменения семантики? 

конечно. Именно так  и нужно перегружать. Что по твоему семантика? Семантика оператора - это его смысл. Смысл оператора "+" в сложении. Вот и перегружать его надо так, чтобы он по смыслу делал сложение. Где тут изменение семантики?
Цитата(d06osipov @  10.6.2008,  09:03 Найти цитируемый пост)
Перегрузка && и ||, как и перегрузка любых других операторов, приводит к изменению их семантики
 правильная перегрузка не должна изменять семантику. Перегрузка стандартных "&&", "||" и "," всегда приводит к изменению семантики, ибо стандартная семантика этих операторов фиксирует порядок вычисления аргументов, и далеко не всегда эти операторы вычисляют оба аргумента, а перегрузка делает их совершенно обычными операторами. Такое поведение нестандартно для этих операторов. Ты в коде видишь a+b и совершенно справедливо ожидаешь от этого выражения сложения. Совершенно справедливо от выражения a||b ожидать того, что делает оператор || , а не обычная функция, аргументами, которой являются  a и b.

Цитата(d06osipov @  10.6.2008,  09:03 Найти цитируемый пост)
(вполне возможно, предыдущая семантика --- ошибка компиляци)

это поведение  не ошибка, а соответствие стандарту. 

Автор: d06osipov 10.6.2008, 10:08
Цитата(Fazil6 @  10.6.2008,  09:58 Найти цитируемый пост)

это поведение  не ошибка, а соответствие стандарту.  


Я имел ввиду вот что:
Код

class A{};

int main()
{ A a1,a2;
  a1||a2;
  return 0;
}

В этом случае --- семантика оператора a1||a2 --- ошибка компиляции.

Цитата(Fazil6 @  10.6.2008,  09:58 Найти цитируемый пост)
Что по твоему семантика? Семантика оператора - это его смысл

Мы с вами по разному понимаем слово семантика. Я вкладываю в него не смысл, а то, что конкретно делает данная сущность (строгое определение во всех деталях), иными словами --- описание изменения состояния машины после выполнение данной сущности. А смысл я называю спецификацией (пример: +. Спецификация: сложить два числа. Семантика: записывает в стек сумму двух чисел без побочных эффектов). В этом случае, перегружать, не меняя семантики --- значит, писать тавтологичный код.

Автор: Fazil6 10.6.2008, 10:17
Цитата(d06osipov @  10.6.2008,  10:08 Найти цитируемый пост)
А смысл я называю спецификацией (пример: +. Спецификация: сложить два числа. Семантика: записывает в стек сумму двух чисел без побочных эффектов). 

Не понимаю. В чем тогда по-твоему изменение семантики при перегрузке "+" для каких-нибудь объектов учитывая, что спецификация не изменилась(сложить два объекта)?

Автор: Alek86 10.6.2008, 10:36
Цитата(d06osipov @  10.6.2008,  10:08 Найти цитируемый пост)
Я вкладываю в него не смысл, а то, что конкретно делает данная сущность (строгое определение во всех деталях), иными словами --- описание изменения состояния машины после выполнение данной сущности. А смысл я называю спецификацией

значит для тебя перегрузка оператора не должна менять его спецификацию
а для оператора "," это не возможно 

Автор: vinter 10.6.2008, 11:17
Код

std::vector<std::string> buffers;
std::string s;
while (std::getline(std::cin, s), !std::cin.eof())
{
  buffers.push_back(s);

}

как это будет работать?
т.е сначала выполняется std::getline(std::cin, s), потом !std::cin.eof(), а что проверяется в while? возвращаемое значение std::getline(std::cin, s)?

Автор: Fazil6 10.6.2008, 11:43
Цитата(vinter @  10.6.2008,  11:17 Найти цитируемый пост)
а что проверяется в while?

последнее, т.е. !std::cin.eof()

Автор: Любитель 10.6.2008, 12:22
Цитата(Fazil6 @  10.6.2008,  09:58 Найти цитируемый пост)
конечно. Именно так  и нужно перегружать. Что по твоему семантика? Семантика оператора - это его смысл. Смысл оператора "+" в сложении. Вот и перегружать его надо так, чтобы он по смыслу делал сложение. Где тут изменение семантики?

В большинстве случаев это верно. Но иногда удобна перегрузка без следования этим правилам. boost::asign, boost::lambda, boost::optiona, etc. - в качестве примеров.

Автор: andrew_121 10.6.2008, 12:45
Это дискуссия, безконечна...
Спорить не буду, за - то же.
Как не крути, но в перегрузке "oprator ," больше негатива, чем позитива.
Так же, перегрузка "||" и "&&" вносит больше подозрений, непонятки, в код ее использующий. Зачем забивать себе голову еще и тем что, нужно помнить что эти операторы перегружены, когда и так у программера в голове, полно всякой полезной, и безполезной информации. Ведь проще написать пару лишних строк, чем забивать себе голову...(имхо)

Автор: JackYF 10.6.2008, 15:04
Цитата(vinter @  10.6.2008,  10:17 Найти цитируемый пост)
а что проверяется в while?

оператор "запятая" возвращает значение последнего аргумента smile

Автор: Lazin 10.6.2008, 15:18
Цитата(JackYF @  10.6.2008,  15:04 Найти цитируемый пост)
оператор "запятая" возвращает значение последнего аргумента

неперегруженый, а перегруженый, может вернуть что угодно smile

Автор: d06osipov 10.6.2008, 15:49
Цитата(Alek86 @  10.6.2008,  10:36 Найти цитируемый пост)
значит для тебя перегрузка оператора не должна менять его спецификацию
а для оператора "," это не возможно  

Согласен. Но в большинстве случаев, программист знает, на что он идёт. И, скажем, если вы разрабатываете библиотеку, перегрузка оператора "," может испортить программу при подключении только в том случае, если:
1. Этот оператор объявлен все namespace, или используется using namespace (в противном случае, при уже существующей встроенной реализации "," будет выбираться пользовательская только в том случае, когда один из операндов имеет тип, находящийся в этом namespace, что не навредит. См. разрешение имён)
2. Этот оператор объявлен для типов, существующих вне библиотеки, например:
template<class T,class S>
T& operator , (const T&,const S&); //так делать не надо

В Boost этот оператор применяется при левом аргументе имеющем совершенно скрытый тип, о котором пользователь даже не знает. Следовательно, этот оператор не может помешать правильной работе программы. 

Оператор "," полезно использовать вместо эллипса! Но надо быть осторожнsм, чтобы компилятор не воспринял , за знак отделения аргументов функции:
Код

class A{};
inline A operator , (A l, A r){return l;}

int f(A)
{
}

int main()
{A a1,a2;
  f(a1,a2); //неверно!
  f((a1,a2)); //вот так
  return 0;
}



Т. о. Перегружать оператор , следует только в том случае, когда тип одного из операндов --- класс, к которому больше никак обращаться не следует.

Автор: Alek86 10.6.2008, 16:11
Цитата(d06osipov @  10.6.2008,  15:49 Найти цитируемый пост)
Но надо быть осторожнsм, чтобы компилятор не воспринял , за знак отделения аргументов функции

помойму это совсем не обязательно, ведь сначала компилер "примеряет" юзерские переопределения, а только потом подставяляет стандартные

Автор: Любитель 10.6.2008, 16:40
Нет, как раз в данном случае сработает вызов функции с двумя параметрами. Поэтому использование запятой как подмены функции с произвольным количеством параметров - не лучшее решение smile

Автор: d06osipov 10.6.2008, 16:53
Цитата(Alek86 @  10.6.2008,  16:11 Найти цитируемый пост)
помойму это совсем не обязательно, ведь сначала компилер "примеряет" юзерские переопределения, а только потом подставяляет стандартные 


Запятая при вызове функции это не переопределение, а синтаксическая конструкция. На тех компиляторах, на которых я пробовал, это воспринималось как разделение аргументов. Не знаю, оговорено ли это явно в Стандарте, или нет, но в любом случае, лучше при использовании запятых заключить аргумент в скобки (как в примере).

Автор: Fazil6 11.6.2008, 09:28
Цитата(d06osipov @  10.6.2008,  16:53 Найти цитируемый пост)
Не знаю, оговорено ли это явно в Стандарте

оговорено. в аргументах без скобок запятая не оператор

Автор: vinter 11.6.2008, 10:02
ммм, всем спасибо за ответы. Спор помоему пошел ни о чем.
Подведу итог: использование запятой ухудшает читабельность кода, но в некоторых случаех запятая удобна(перегруженная) как в случае с boost.
Всем спасибо за ответы.

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