"встроенные" операторы vs простая функция
От: TheAteist  
Дата: 27.05.10 20:58
Оценка:
Помогите ответь на заданный вопрос. Прошу не спрашивайте откуда взят этот вопрос, а просто помогите ответить.
Какие свойства(семантические и/или синтаксические) есть у "встроенных" операторах, которые отличают их от простоты функций?

Как я понял, то имееться ввиду,например, использование
cout << myObject;

вместо
myObject.print();//или print(myObject);


А какие свойства...?
Большое спасибо.

28.05.10 02:50: Перенесено модератором из 'C/C++. Прикладные вопросы' — Кодт
Re: "встроенные" операторы vs простая функция
От: Кодт Россия  
Дата: 27.05.10 22:50
Оценка:
Здравствуйте, TheAteist, Вы писали:

TA>
TA>cout << myObject;
TA>

Это не встроенный оператор, а перегруженный.
Всего лишь инфиксная запись функции ostream& ::operator<<(ostream&, const T&)
либо функции-члена ostream& ostream::operator<<(const T&)
Встроенный << это оператор сдвига для целых чисел.

У функций бывают дефолтные аргументы, а у операторов нет.
У шаблонов функций можно указывать параметры явно: foo<int>(x) и-или выводить из типов аргументов, у шаблонов операторов параметры выводятся.
Оператор-член и оператор-свободная функция выглядят одинаково: cout << x. Естественно, что если оператор-член, то объект — это его левый аргумент.
У операторов немножко другой порядок поиска перегрузок (argument-dependent lookup), чем у функций. Об этом лучше у отцов-основателей почитать, у Саттера, кажется, было разжёвано.

Какие ещё свойства интересуют?
Перекуём баги на фичи!
Re[2]: "встроенные" операторы vs простая функция
От: TheAteist  
Дата: 28.05.10 07:46
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Какие ещё свойства интересуют?

Честно, то я не знаю какие еще свойства. Я надейлся здесь получить ответа.
Буду рад за помощь.

Спасибо.
Re[3]: "встроенные" операторы vs простая функция
От: Кодт Россия  
Дата: 28.05.10 08:04
Оценка:
Здравствуйте, TheAteist, Вы писали:

К>>Какие ещё свойства интересуют?

TA>Честно, то я не знаю какие еще свойства. Я надейлся здесь получить ответа.
TA>Буду рад за помощь.

Чтобы не отвечать наугад, — лучше всё-таки расскажи, откуда взялся вопрос.
Перекуём баги на фичи!
Re[2]: "встроенные" операторы vs простая функция
От: remark Россия http://www.1024cores.net/
Дата: 28.05.10 08:08
Оценка:
Здравствуйте, Кодт, Вы писали:

К>У функций бывают дефолтные аргументы, а у операторов нет.

К>У шаблонов функций можно указывать параметры явно: foo<int>(x) и-или выводить из типов аргументов, у шаблонов операторов параметры выводятся.
К>Оператор-член и оператор-свободная функция выглядят одинаково: cout << x. Естественно, что если оператор-член, то объект — это его левый аргумент.
К>У операторов немножко другой порядок поиска перегрузок (argument-dependent lookup), чем у функций. Об этом лучше у отцов-основателей почитать, у Саттера, кажется, было разжёвано.

Ещё у операторов приоритеты разные, зависит от того, через какой именно оператор мы реализовали функциональность. А для функций приоритет всегда один.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[2]: "встроенные" операторы vs простая функция
От: slava_phirsov Россия  
Дата: 28.05.10 08:52
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Какие ещё свойства интересуют?


А еще для операторов определен порядок вычисления аргументов, для логических операторов — "логическое К.З.". Е.М.Н.И.П., в best-practices от Майерса именно по этой причине не рекомендуется перегружать операторы "запятая" и логические операторы.
Люди! Люди, смотрите, я сошел с ума! Люди! Возлюбите друг друга! (вы чувствуете, какой бред?)
Re[3]: "встроенные" операторы vs простая функция
От: vermont  
Дата: 28.05.10 08:57
Оценка:
Здравствуйте, TheAteist, Вы писали:

TA>Честно, то я не знаю какие еще свойства. Я надейлся здесь получить ответа.

TA>Буду рад за помощь.

Перегруженный оператор удобнее использовать для вывода в любой поток, не только в cout (например в ostringstream).
Кроме этого, Вы можете использовать оператор для вывода в поток контейнера элементов с помошью
ostream_iterator.

    copy(v.begin(), v.end(), ostream_iterator<Type>(cout, ", "));
Re[3]: "встроенные" операторы vs простая функция
От: Кодт Россия  
Дата: 28.05.10 10:27
Оценка: 4 (1)
Здравствуйте, slava_phirsov, Вы писали:

_>А еще для операторов определен порядок вычисления аргументов, для логических операторов — "логическое К.З.". Е.М.Н.И.П., в best-practices от Майерса именно по этой причине не рекомендуется перегружать операторы "запятая" и логические операторы.


Порядок определён для встроенных операторов «&&», «||» и «,». А для перегруженных — не определён, равно как и для любых других функций.
Это вносит визуальную сумятицу, поскольку два внешне однообразных выражения работают по-разному.

Оператор «,» отличается ещё и тем, что
— встроенный оператор может получать тип void
— он всеяден — там, где с другим оператором была бы ошибка компиляции (нет подходящей сигнатуры), с запятой всегда наготове встроенный оператор
Перекуём баги на фичи!
Re[4]: "встроенные" операторы vs простая функция
От: TheAteist  
Дата: 28.05.10 12:06
Оценка:
Здравствуйте, Кодт, Вы писали:

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


_>>А еще для операторов определен порядок вычисления аргументов, для логических операторов — "логическое К.З.". Е.М.Н.И.П., в best-practices от Майерса именно по этой причине не рекомендуется перегружать операторы "запятая" и логические операторы.


К>Порядок определён для встроенных операторов «&&», «||» и «,». А для перегруженных — не определён, равно как и для любых других функций.

К>Это вносит визуальную сумятицу, поскольку два внешне однообразных выражения работают по-разному.

К>Оператор «,» отличается ещё и тем, что

К>- встроенный оператор может получать тип void
К>- он всеяден — там, где с другим оператором была бы ошибка компиляции (нет подходящей сигнатуры), с запятой всегда наготове встроенный оператор

Спасибо.
Просто есть курс "Языки программирования"(не в России) и был задан вот такой вопрос.
Если есть еще что-то, буду блогадарен.
Re[5]: "встроенные" операторы vs простая функция
От: DmitryShm Россия https://ipshmykov.ru/
Дата: 30.05.10 01:29
Оценка: -3
Здравствуйте, TheAteist, Вы писали:

TA>Если есть еще что-то, буду блогадарен.


Он будет благодарен. Учебники по С++ есть, ёкарный бабай.
Re[4]: "встроенные" операторы vs простая функция
От: Aleх  
Дата: 30.05.10 22:47
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Порядок определён для встроенных операторов «&&», «||» и «,». А для перегруженных — не определён, равно как и для любых других функций.

К>Это вносит визуальную сумятицу, поскольку два внешне однообразных выражения работают по-разному.

Под порядком подразумевается порядок вычисления аргументов, а не приоритет операторов, я надеюсь?

Чтобы не было сумятицы, нужно писать код, который бы не зависел от порядка вычисления аргументов, то есть без побочных эффектов.
Re[5]: "встроенные" операторы vs простая функция
От: Кодт Россия  
Дата: 31.05.10 08:10
Оценка:
Здравствуйте, Aleх, Вы писали:

A>Под порядком подразумевается порядок вычисления аргументов, а не приоритет операторов, я надеюсь?

Естественно. И это, кстати, ещё одна боль для программистов-новичков. Причём не только с операторами — а даже с вызовом функций.

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

Твои бы слова да богу в уши
Перекуём баги на фичи!
Re[5]: "встроенные" операторы vs простая функция
От: slava_phirsov Россия  
Дата: 31.05.10 13:29
Оценка: -1
Здравствуйте, Aleх, Вы писали:

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


Увы, иногда Париж стоит мессы. Пример:

if (some_string.size() && some_string[0])
{
...
}


ИМХО гораздо лучше, чем:

if (some_string.size())
 if some_string[0])
 {
  ...
 }


В первом случае мы используем "логическое К.З.". Если бы порядок вычисления аргументов оператора && был неопределен, или всегда требовалось бы вычислять оба аргумента, то можно было бы использовать только 2-й вариант. Это, конечно, мое личное ИМХО
Люди! Люди, смотрите, я сошел с ума! Люди! Возлюбите друг друга! (вы чувствуете, какой бред?)
Re[6]: "встроенные" операторы vs простая функция
От: slava_phirsov Россия  
Дата: 02.06.10 09:01
Оценка:
Уважаемый DmitryShm! За "минус" спасибо, жду развернутого объяснения, с чем именно в моем посте Вы не согласны.
Люди! Люди, смотрите, я сошел с ума! Люди! Возлюбите друг друга! (вы чувствуете, какой бред?)
Re[5]: "встроенные" операторы vs простая функция
От: slava_phirsov Россия  
Дата: 04.06.10 13:01
Оценка:
Здравствуйте, Aleх, Вы писали:

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


P.S. Вот например такой код 100% зависит от порядка вычисления аргументов, и обойтись без этого ээээээ довольно проблематично:


foo = bar(foo);


"=" тоже является оператором, как ни странно, причем его тоже можно перегрузить... А foo, как ты, конечно, заметил, содержится в обеих частях выражения
Люди! Люди, смотрите, я сошел с ума! Люди! Возлюбите друг друга! (вы чувствуете, какой бред?)
Re[6]: "встроенные" операторы vs простая функция
От: Кодт Россия  
Дата: 04.06.10 14:05
Оценка:
Здравствуйте, slava_phirsov, Вы писали:

_>
_>foo = bar(foo);
_>


_>"=" тоже является оператором, как ни странно, причем его тоже можно перегрузить... А foo, как ты, конечно, заметил, содержится в обеих частях выражения


Неудачный пример.
Перегрузить = можно только как член класса, и тогда слева ссылка. Либо это встроенный оператор, и тогда опять слева ссылка.
Адрес объекта не меняется из-за операций над ним, поэтому нам всё равно, что произошло раньше — взяли this=&foo или value=bar(foo), перед тем, как применить operator=(this,value).
И если bar — это вызов функции, то возникают точки следования на входе и выходе из неё, поэтому никакого undefined behavior быть не может, а почву для unspecified behavior мы не сделали.
Вот если bar — это макрос, развёртывающийся в foo++ какое-нибудь, и всё это со встроенными операторами, — то здесь мы точно отхватим UB.

Но, если вместо = написать += (или любой другой), который можно перегружать как свободную функцию... Вот там можно передавать левый аргумент и по значению, и как угодно.
Это даст нам unspecified behavior (аукнется в тех случаях, когда компилятор решит оптимизировать конвенцию cdecl и вычислить левый аргумент раньше правого).

Вот пример, который хорошо оптимизируется и, как следствие, крайне чувствителен к порядку вычислений.
#include <iostream>
using namespace std;

enum V { vmin=INT_MIN, vmax=INT_MAX };

struct X
{
    int n;
    explicit X(int n) : n(n) {}
    operator V() const { return V(n); }
};

V operator + (V a, V b)
{
    cout << int(a) << "+" << int(b) << "=" << (int(a)+int(b)) << endl;
    return V(int(a)+int(b));
}

V bar(X& x)
{
    cout << "bar(" << x.n << ")";
    x.n += 100;
    cout << "=" << x.n << endl;
    return x;
}

int main()
{
    X foo(10);
    V v = foo + bar(foo) + bar(foo) + bar(foo);
    cout << int(v);
}

Без оптимизации (VC8 /Od, g++3.4.4 -O0)
bar(10)=110
bar(110)=210
bar(210)=310
310+310=620
620+210=830
830+110=940
940

Максимальная оптимизация (VC8 /Ox, g++3.4.4 -O3)
bar(10)=110
10+110=120
bar(110)=210
120+210=330
bar(210)=310
330+310=640
640
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.