#include <iostream.h>
int main ()
{
enum m {a,f,h,j,y,t};
m jj = a;
jj++;
return 0;
}
Ругается:
1.cpp: In function `int main()':
1.cpp:6: error: no `operator++(int)' declared for postfix `++', trying prefix
operator instead
1.cpp:6: error: no match for 'operator++' in '++jj'
Допишите пожалуйста пример...., я не могу понять синтаксис operator-a.
operator++ (Как им пользоваться???)
Модератор: Модераторы разделов
-
Asgard
- Сообщения: 215
- Статус: North Valfader
Re: operator++
а что вы, собственно, ожидали, применяя оператор ++ к enum'у?
enum фактически является перечислением констант.
что же касается операторов:
enum фактически является перечислением констант.
что же касается операторов:
Код: Выделить всё
class SomeClass {
private:
int member;
/*...*/
public:
/*...*/
SomeClass(): member(0) {}
void operator++() { ++member; } // prefix
SomeClass& operator++(int) { return ++(*this); } // postfix
/*...*/
};-
ToniX
- Сообщения: 11
Re: operator++
Компилятор совершенно справедливо указывает на ошибку, т. к для enum'ов по умолчанию не определены операторы ++/--. И это не случайно: enum - встроенный тип, по сути представляющий собой конечное множество именованных целочисленных констант. Т. к. множество не только конечно, но и, в общем случае, не последовательно (enum { a = 0, b = 100, c = 1000 }), то компилятор не может сгенерировать быстрый и эффективный код для операторов ++/--. Можно конечно для некоторых частных случаев извратиться на подобии:
Но польза в таких операторах видеться мне сомнительной; да и само применение reinterpret_cast давольно красноречиво говорит о “чистоте” подобного подхода. Использование такого решения – верный способ нажить себе неприятностей при сопровождении и расширении программы.
Так что, если всё же возникла необходимость в подобной функциональности, то IMHO лучше обернуть enum в класс, и работать с операторами ++/-- уже на уровне класса.
Извеняюсь, для postfix-формы оператора ++ следовало было возвращать не ссылку, а значение:
Код: Выделить всё
enum SomeEnum { first = 0, second, third, last };
// prefix
SomeEnum &operator ++(SomeEnum &se)
{
if( se == last ) {
se = first;
}
else {
int proxy = se;
++proxy;
se = *reinterpret_cast<SomeEnum *>(&proxy);
}
return se;
}
// postfix
SomeEnum &operator ++(SomeEnum &se, int)
{
SomeEnum old = se;
++se;
return old;
}Но польза в таких операторах видеться мне сомнительной; да и само применение reinterpret_cast давольно красноречиво говорит о “чистоте” подобного подхода. Использование такого решения – верный способ нажить себе неприятностей при сопровождении и расширении программы.
Так что, если всё же возникла необходимость в подобной функциональности, то IMHO лучше обернуть enum в класс, и работать с операторами ++/-- уже на уровне класса.
Извеняюсь, для postfix-формы оператора ++ следовало было возвращать не ссылку, а значение:
Код: Выделить всё
// postfix
SomeEnum operator ++(SomeEnum &se, int)
{
SomeEnum old = se;
++se;
return old;
}-
GRS
- Сообщения: 236
- Статус: C++ Pro
- ОС: Suse10.2/XP
Re: operator++
Операторы ++, -- в основном применяются для указателей и счетчиков в циклах.
Для указателей это хорошо тем, что нет необходимости вычислять адрес по индексу массива. Конечно есть минус нету произвольного доступа.
Вторая цель использования счетчика в циклах. Просто, удобно и красиво. Отметил бы только то, что:
Будет работать быстрее, чем:
Т.к. ++i не возвращает временный объект.
Простой пример, объясняющий принцип работы операторов ++ и --.
Для указателей это хорошо тем, что нет необходимости вычислять адрес по индексу массива. Конечно есть минус нету произвольного доступа.
Вторая цель использования счетчика в циклах. Просто, удобно и красиво. Отметил бы только то, что:
Код: Выделить всё
for (int i = 0; i < ANY_SIZE; ++i)Будет работать быстрее, чем:
Код: Выделить всё
for (int i = 0; i < ANY_SIZE; i++)Т.к. ++i не возвращает временный объект.
Допишите пожалуйста пример...., я не могу понять синтаксис operator-a.
Простой пример, объясняющий принцип работы операторов ++ и --.
Код: Выделить всё
int i = 4, j = 7;
int res = ++i; // res = 5. i = 5
res = j--; // res = 7, j = 6
res = i++; // res = 5, i = 6
res = --j; // res = 5, j = 5-
elide
- Бывший модератор
- Сообщения: 2421
- Статус: Übermensch
- ОС: лялих
Re: operator++
компиляторы сейчас не дураки пошли..... если этот самый временный объект не используется, то он и не возвращается. так что, и дляТ.к. ++i не возвращает временный объект.
Код: Выделить всё
for (int i = 0; i < ANY_SIZE; ++i)Код: Выделить всё
for (int i = 0; i < ANY_SIZE; i++)слава роботам!
-
ToniX
- Сообщения: 11
Re: operator++
компиляторы сейчас не дураки пошли..... если этот самый временный объект не используется, то он и не возвращается. так что, и для
и дляКод: Выделить всё
for (int i = 0; i < ANY_SIZE; ++i)
Код: Выделить всё
for (int i = 0; i < ANY_SIZE; i++)
набор инструкций оказывается тот-же даже в самом простом случае.
Для простейших случаев это, возможно, и сработает (да и то не факт), но, например, как быть со следующим примером:
Код: Выделить всё
#include <vector>
typedef std::list<int> MyList;
/*
......
*/
MyList l;
UseMyList(l);
for( MyList::iterator it = l.begin(); it != l.end(); it++ ) // ???????
/* .... */;Компилятор должен создать как минимум одну копию итератора (он может оптимизировать возврат значения, и вместо двух копий создать одну), так как создание класса – уже есть его использование и код будет менее эффективным (возможно значительно), чем в случае ++it. А использовать разные формы оператора ++, в зависимости от "сложности" используемой конструкции IMHO плохой стиль, причем ничем не оправданный. Поэтому я всегда использую префиксную форму, за исключением некоторых (довольно редких) случаев, когда постфиксный оператор обеспечивает более наглядный, короткий и понятный код.
-
elide
- Бывший модератор
- Сообщения: 2421
- Статус: Übermensch
- ОС: лялих
Re: operator++
ToniX
а что тебе мешает не задрачивать мозг, а взять и попробовать?
даю, типа, хинт: у g++ есть опция -S, при указании которой, он собственно и компилирует указанный файл.
итак, имеем:
итого: одна единственная строчка различий в названии файлов.
а что тебе мешает не задрачивать мозг, а взять и попробовать?
даю, типа, хинт: у g++ есть опция -S, при указании которой, он собственно и компилирует указанный файл.
итак, имеем:
Код: Выделить всё
elide@rebirth| ~/exp/c/test/increment >> cat prefix.cpp
#include <list>
#include <iostream>
using namespace std;
int main(){
list<int> l;
l.push_back(5);
l.push_back(6);
for( list<int>::iterator it = l.begin(); it != l.end(); ++it )
cout << *it << endl;
return 0;
}Код: Выделить всё
elide@rebirth| ~/exp/c/test/increment >> diff prefix.cpp postfix.cpp
8c8
< for( list<int>::iterator it = l.begin(); it != l.end(); ++it )
---
> for( list<int>::iterator it = l.begin(); it != l.end(); it++ )Код: Выделить всё
elide@rebirth| ~/exp/c/test/increment >> g++ -S prefix.cpp
elide@rebirth| ~/exp/c/test/increment >> g++ -S postfix.cpp
elide@rebirth| ~/exp/c/test/increment >> diff prefix.s postfix.s
1c1
< .file "prefix.cpp"
---
> .file "postfix.cpp"
elide@rebirth| ~/exp/c/test/increment >>слава роботам!
-
ToniX
- Сообщения: 11
Re: operator++
elide писал(а): ↑23.05.2006 20:27ToniX
а что тебе мешает не задрачивать мозг, а взять и попробовать?
даю, типа, хинт: у g++ есть опция -S, при указании которой, он собственно и компилирует указанный файл.
итак, имеем:Код: Выделить всё
elide@rebirth| ~/exp/c/test/increment >> cat prefix.cpp #include <list> #include <iostream> using namespace std; int main(){ list<int> l; l.push_back(5); l.push_back(6); for( list<int>::iterator it = l.begin(); it != l.end(); ++it ) cout << *it << endl; return 0; }
Код: Выделить всё
elide@rebirth| ~/exp/c/test/increment >> diff prefix.cpp postfix.cpp 8c8 < for( list<int>::iterator it = l.begin(); it != l.end(); ++it ) --- > for( list<int>::iterator it = l.begin(); it != l.end(); it++ )итого: одна единственная строчка различий в названии файлов.Код: Выделить всё
elide@rebirth| ~/exp/c/test/increment >> g++ -S prefix.cpp elide@rebirth| ~/exp/c/test/increment >> g++ -S postfix.cpp elide@rebirth| ~/exp/c/test/increment >> diff prefix.s postfix.s 1c1 < .file "prefix.cpp" --- > .file "postfix.cpp" elide@rebirth| ~/exp/c/test/increment >>
Во-первых, мир состоит не только из компилятора gcc и твоей платформы. Во-вторых, оператор ++ применяется далеко не только к встроенным типам и итераторам стандартных контейнеров. И что, для каждого контейнера или класса, попавшего тебе в руки, ты будешь проверять, сможет ли твой ДАННЫЙ компилятор, на ДАННОЙ платформе сгенерировать одинаково эффективный код для двух версий оператора ++?
Чтобы не быть голословным, я взял компилятор gcc-3.4.2 под Windows XP (MinGW) и прогнал твои примеры. Результат таков: 1187 строк дизассемблерного листинга prefix против 1192 postfix. Основные различия, как и следовало ожидать, в реализации операторов ++ для итератора.
Да и вообще, рассчитывать на оптимизатор конкретного компилятора - дело весьма рискованное. Качество оптимизации меняется от компилятора к компилятору (да и от версии к версии одного и того же компилятора), и воспринимать ее надо как дополнительный бесплатный бонус, а не как надежный аргумент к выбору той или иной конструкции языка. Тем более в данном случае для избежания зависимости от оптимизатора достаточно переставить два символа из конца идентификатора в начало; смешно, неправда ли? Да и вообще, IMHO голова гораздо более мощный оптимизатор, чем имеется у компилятора. Так зачем же ее отключать в угоду весьма сомнительным стилистическим удобствам?