LINUX.ORG.RU

[C++] перегрузка оператора <<запятая>>

 


0

1

Есть некторый класс A, для которого перегужен оператор запятая, для базовых типов как оператор класса, для некоторых классов как внешний:

class A{
...
   A& operator , ( int v ){ ...; return *this; }
};

template <class T> A& operator, ( A& a, const B<T> & b ){ ...; return a; }

A(...), expr1, expr2, ... ;

Если результат первого выражения в цепочке относится к базовым типам, все работает. Если результат первого выражения относится к B<...> то рабтает встроенная реализация (т.е. перегруженный оператор не вызвается). Как бы заставить его рабоать и во втором случае?

★★★★★

помницо я пытался оверлодить << (чтобы дампить через cout) для какого-то своего темплейтного убогого класса, долго парил моск, грепал хидеры буста. точное решение не помню но было что-то типа template <class T> перед классом, template <class U> перед методом :3

anonymous
()

> A(...), expr1, expr2, ... ;

Покажите реальный пример использования, а не абстрактный.

anonymous
()
Ответ на: комментарий от anonymous

Вот наглядно иллюстрирующий вопрос тест:

 #include <stdio.h>

class A{ 
public:    
    A& operator, ( int ){ printf("A::int\n"); return *this; } 
};

template < class T > class B{};

template < class T > A& operator , ( A& a, const B<T> & b ) { printf("B\n"); return a; }

int main(){    
     B<double> b;    
     A(), 1, b;    
     A(), b, 1;    
     return 0; 
} 

в итоге получается так

 
tmp> g++ test.cpp 
tmp> ./a.out 
A::int 
B 

а должно бы быть так

 
A::int 
B 
B 
A::int 

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv
#include <stdio.h>

class A{
public:
    const A& operator, ( int ) const { printf("A::int\n"); return *this; }
};

template < class T > class B{};

template < class T > const A& operator , ( const A& a, const B<T> & b ) { printf("B\n"); return a; }

int main(){
     B<double> b;
     A(), 1, b;
     A(), b, 1;
     return 0;
}

(добавились const, т.к. A() временный объект и по ссылке не передается)

Выхлоп:

A::int
B
B
A::int

dmage
()
Ответ на: комментарий от AIv

> A(), 1, b;

Ничего, что A() это временный объект? Попробуйте скомпилировать с -Wall.

anonymous
()
Ответ на: комментарий от dmage

Виноват что сразу не сказал - он не может быть const т.к. с ним всякие манипуляции происходят.

В принципе для меня это решение (можно делать A a; a, expr1, expr2, ...; - так и прада работает, все равно это все в недрах макроса прячется), но тогда вопрос - а как работает второе звено первой цепочки? Или объект, вернувшийся из первого оператора уже не считается временным?

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

> Или объект, вернувшийся из первого оператора уже не считается временным?

Временный и константный, т.к. первый оператор возвращает константную ссылку.

anonymous
()
Ответ на: комментарий от dmage

А с какой вообще стати запись

A(), 1;
корректна, если тип А() неопределен? Получите свой undefined behaviour и распишитесь.

anonymous
()
Ответ на: комментарий от anonymous

> Временный и константный, т.к. первый оператор возвращает константную ссылку.

это в примере dmage константантынй, а у меня нет, см выше.

если тип А() неопределен

А с какой стати типа A неопределен?

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

> А с какой стати типа A неопределен?

А с какой стати определен, если конструктор никакого типа не возвращает?

anonymous
()
Ответ на: комментарий от anonymous

> А с какой стати определен, если конструктор никакого типа не возвращает?

Что за лжеанонимус порочит мою честь?! Прочь с моего лора!

anonymous
()
Ответ на: комментарий от anonymous

Даже не знаю что Вам ответить... есть наверное ЯП в которых контруктор что то возвращает, но я с ними незнаком. Мне всегда наивно казалось, что память под структуру выделят компайлер, конструктор ее инициализарует, и запись A() означает создать экземпляр класса типа А. Как то так...

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

> это в примере dmage константантынй, а у меня нет, см выше.

Первый ваш пример (A(...), expr1, expr2, ... ;) у вас некорректный с точки зрения языка. Именно поэтому я вам предложил скомпилировать его с -Wall.

Во втором вашем примере (A a; a, expr1, expr2, ...;) первая цепочка вернет ссылку на объект a.

anonymous
()
Ответ на: комментарий от anonymous

Секундочку. Цепочка A(),b,1; и правда выдает ворнинги right-hand operand of comma has no effect

Но цепочка A(),1,b; ничего не выыдает и корректно работает! Чем же тогда A(),1 отчитается от A()? И то и то временные объекты, нет?

AIv ★★★★★
() автор топика
Ответ на: комментарий от anonymous

> А ты думаешь, что конструктор что-то возвращает? Интересно тогда, что?

Конструктор ничего не возвращает. Указанная конструкция в С++ рассматривается как создание временного объекта, который и будет передан в функцию.

Если бы ты хоть чуть-чуть владел С++, то знал про это. Вот тебе еще пара примеров:

Object o = Object();

f(std::string(«hello»));

anonymous
()
Ответ на: комментарий от anonymous

результатом работы A() является экземпляр класса A. Будете спорить?;-)))

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

Объясняю на пальцах. Цепочка A(),b,1 конвертируется в конструкцию:

operator,(operator,(A(), b), 1);

Эта конструкция не правильная с точки зрения языка т.к. нельзя передавать временный объект по неконстантной ссылке. В идеале она даже не должна компилироваться, но компилятор в данном случае идет вам на уступки.

Скорее всего если вы потребуете от компилятора строго следования С++, то программа даже не скомпилируется.

anonymous
()
Ответ на: комментарий от AIv

Продолжаю объяснять на пальцах. Цепочка A(),1,b конвертируется в конструкцию:

operator,(A().operator,(1), b)

Здесь компилятор не может определить, что результатом A().operator,(1) будет неконстантная ссылка на временный объект. Вот и все.

anonymous
()
Ответ на: комментарий от anonymous

А цепочка A(),1,b конвертируется в

operator,(A().operator,(1), b);

и по каким то своим внутренним мотивам компилятор считает конструкцию A().operator,(1) корректной и ее результат не временным объектом? Мдя... ИМНО весьма нелогично с его стороны.

Всем спасибо, будем считать что я понял и знаю как с этим бороться;-)

AIv ★★★★★
() автор топика
Ответ на: комментарий от anonymous

> Тем, что A(),1 возвращает А, а что возвращает А()?

Лжеанонимус, прекрати хулиганство и займись делом. Например, почитай книжку по С++.

anonymous
()
Ответ на: комментарий от AIv

> и по каким то своим внутренним мотивам компилятор считает конструкцию A().operator,(1) корректной и ее результат не временным объектом?

В идеале он бы мог это сделать, но это затратно: компилятор должен проанализировать реализицию метода operator, а она может находиться, например, в другой единице трансляции.

anonymous
()
Ответ на: комментарий от AIv

> все равно это все в недрах макроса прячется

По вашим постам у вас сплошь и рядом макросы. Рекомендую призадуматься об этом. Кроме того, не стоит перегружать лишний раз такие операторы как ",".

anonymous
()
Ответ на: комментарий от anonymous

Прикольно... т.е. это способ обойти это ИМНО дурачкое ограничение на неконcтанные ссылки и временные объекты. Достаточно ввести метод

class A{
...
A& ref2me(){ return *this; }
}
void myfunc( A& );


и потом

myfunc( A().ref2me() );

?;-)

AIv ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Указанная конструкция в С++ рассматривается как создание временного объекта, который и будет передан в функцию.

Кого волнуют эти костыли? Факт в том, что эта конструкция ничего не возвращает по определению и ее использование в таком контексте заведомо некорректно. И дело в сабже не во временных объектах, а именно в этой некорректности. Ты же несешь полную чушь. Вот например:

 #include <stdio.h>

class A{ 
public:    
    A& operator, ( int ){ printf("A::int\n"); return *(new A()); } 
};

template < class T > class B{};

template < class T > A& operator , ( A& a, const B<T> & b ) { printf("B\n"); return *(new A()); }

int main(){    
     B<double> b;    
     A(), 1, b;    
     A(), b, 1;    
     return 0; 
}
Теперь нету никаких временных объектов, но ничего все равно не работает. А вот так:
int main(){    
     B<double> b;    
     *(new A()), 1, b;    
     *(new A()), b, 1;    
     return 0; 
}
работает. Аргументы второй запятой в этих двух случаях совершенно одинаковы, дело именно в первой запятой.

anonymous
()
Ответ на: комментарий от anonymous

Далеко не сплошь, просто мне иногда надо от С++ то, что кроме как через макросы и не сделаешь никак;-) Ну или С++0х отчасти может помочь, но это дело пока мутное.

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

> это способ обойти это ИМНО дурачкое ограничение на неконcтанные ссылки и временные объекты

Это вовсе не дурацкое ограничение, а здравый смысл и обходить такие ограничения не стоит.

anonymous
()
Ответ на: комментарий от AIv

А связка макрос + запятая позволяет обработать список выражений expr1, expr2, ... как строку «expr1, expr2, ...» и затем как список выражений. Я честно говоря не знаю другого способа это сделать... а для вывода отладочной информации ну очень удобно;-)

AIv ★★★★★
() автор топика
Ответ на: комментарий от anonymous

В С++0х специальную конструкцию ввели для обхода этого ограничения, так что не такой уж он и здравый.

AIv ★★★★★
() автор топика
Ответ на: комментарий от anonymous

> Теперь нету никаких временных объектов

Ты укуренный что ли?

A(), 1, b; // создается временный объект A()

A(), b, 1; // создается временный объект A()

anonymous
()
Ответ на: комментарий от anonymous

И что, что он создается? На вторую запятую он все равно не влияет, потому что аргумент второй запятой будет - *(new A()), который нифига не временный. А в первую запятую временный объект засунуть можно без проблем - это аналог твоих примеров Object o = ... Или по твоей логике компилятор любую ссылку, возвращаемую из любой функции, считает «на всякий случай» ссылкой на временный объект? Не неси чепухи.

anonymous
()
Ответ на: комментарий от anonymous

Напр я пишу в коде

WOUT( a, a+b, sqrt(b) );

и получаю на стандартный вывод

#myfile.cpp 123: a=1 a+b=5 sqrt(b)=2

WOUT - макрос с переменынм число аргументов, к-й создает некий объект с перегруженным опертораром запятая, сует ему в конструктор строку «a, a+b, sqrt(b)», информацию о файле и строке кода, а потом приставялет чрез запятую те же аргументы но уже как последовательность выражений. Объект разбирает строку по запятым и по каждой запятой выодит очередное выражение. Если перегрузить запятую для сових объектов удасться выводить и их. КОнечо можно перегрузить скажем << и писать

WOUT( a << a+b << sqrt(b) );

но запятая ИМНО синтаксически наглядней, и потом всякие другие операторы могут использоваться в выражениях.

AIv ★★★★★
() автор топика
Ответ на: комментарий от anonymous

> Факт в том, что эта конструкция ничего не возвращает по определению и ее использование в таком контексте заведомо некорректно. И дело в сабже не во временных объектах, а именно в этой некорректности.

Глупенький ты наш )))

Ты же несешь полную чушь.

А еще и забавный )))

anonymous
()
Ответ на: комментарий от anonymous

> Так что, ты можешь объяснить, почему A(), b не работает? Не можешь? Ну так иди и ртфм тогда.

Я конечно понимаю, что ни одной книжки по плюсам ты не осилил, но хотя бы осиль внимательно перечитать весь топик. В любом случае кому надо тот уже все понял.

anonymous
()
Ответ на: комментарий от anonymous

Девочки, ну не ругайтесь;-)

Главное что я уже все понял, было весьма полезно, спасибо.

Как то я в вас запутался, но теза что A() ничего не возвращает мне представляется сомнительной. В том смысле, что внутри метода можно говорить о том, что он возвращает, а если смотреть на выражение снаружи, то имеет смысл говорить о том, что является результатом выражения. A(), b не работает потому, что временный объект низя сунуть по некностантной ссылке в ф-ю, и компилер рассматривает запятую как не перегруженную. Будь это другой оператор, свалился бы с ошибкой.

AIv ★★★★★
() автор топика
Ответ на: комментарий от VladimirMalyk

>печалят сабжевые фичи

Пойду я выпью сока Ричи
И посмотрю в окно...
А тут все тускло и убого
И анаонимус у порога
На перевес с веслом!

Не печальтесь, все будет хорошо!;-)

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

Кстати говоря, компилятор из VS даже на -W2 выдает предупреждение на конструкцию A(), b, 1; :

warning C4239: nonstandard extension used : 'argument' : conversion from 'A' to 'A &' A non-const reference may only be bound to an lvalue

anonymous
()

> [C++] перегрузка оператора <<запятая>>
Не надо, прошу.

PayableOnDeath
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.