2015-01-21 1 views
13

Почему можно наложить std::ostream на указатель void? Я не знаю ни одного такого оператора преобразования в std::ostream. Код нижеПочему std :: cout конвертируется в void * при использовании g ++?

#include <iostream> 

int main() 
{ 
    void *p = std::cout; // why does this work? 
} 

Я задаю этот вопрос, так как я видел оператор размещения new вызывается как

Foo* pFoo = new (std::cerr) Foo; 

и не имеет ни малейшего представления, почему бы один написать такую ​​вещь.

PS: Я компилирую с g ++ 4.9.2 с или без -std=c++11. clang ++ не принимает код.

PSS: Найдено, что из-за так называемой «безопасную проблему BOOL» (см @ ответ nicebyte в), в предварительно C++ 11 оператор а void* преобразования был определен для std::ostream, который затем был удален в C++ 11 , Тем не менее, мой код компилируется в C++ 11, используя g ++. Более того, clang ++ отвергает его независимо от того, какую версию стандарта я использую, даже с -std=c++98, хотя я понимаю, что он должен принимать, если скомпилирован как pre-C++ 11.

+0

'new (std :: cerr) Foo'? Какие. . Ад. – Quentin

+0

@Quentin :) Вот что я сказал себе, когда увидел это. – vsoftco

+1

Мне бы это понравилось, если бы вы могли предоставить источник. Я могу только думать о ужасных вещах, к которым это может привести. – Quentin

ответ

11

Прочитано this (на ваш вопрос ответили в самом последнем разделе, «Безопасная проблема bool»).

Чтобы разработать немного, реализация определяет неявное преобразование в void*, определенный для таких вещей, как std::cin и std::cout, просто так, что код, как while(std::cin>>x){...} компиляций, в то время как код, как int x = std::cin; нет. Это все еще проблематично, потому что вы можете писать такие вещи, как в вашем примере.

C++ 11 решает эту проблему путем введения явных преобразований.

Оператор преобразования явно выглядит следующим образом:

struct A { 
explicit operator B() { ... } // explicit conversion to B 
}; 

Если А имеет явное преобразование в B, код, как это становится легальным:

A a; 
B b(a); 

Однако код, как это не так:

A a; 
B b = a; 

Конструкция типа if(std::cin) требует: cin, который должен быть преобразован в bool, стандарт утверждает, что для того, чтобы преобразование было действительным в этом конкретном случае, код, такой как bool x(std::cin);, должен быть «законным». Это может быть достигнуто путем добавления явного преобразования в bool. Он позволяет использовать cin/cout в вышеуказанном контексте, избегая при этом таких вещей, как int x = std::cout;.

Для получения дополнительной информации см. Bjarne's page, а также this question.

+1

Помните, что это больше не работает с C++ 11 ... –

+0

Я отредактировал свой ответ, чтобы предоставить более подробную информацию (и также включил информацию о C++ 11). – nicebyte

+1

@nicebyte, спасибо, знал о явных операторах, но не знал, что существует 'void *' оператор преобразования для 'std :: ostream'. Однако в C++ 11 кажется, что это 'void *' conversion было устранено из-за введения явного преобразования в 'bool'. Однако мой код по-прежнему работает даже с '-std = C++ 11' в' g ++ ', поэтому я предполагаю, что это ошибка в реализации libstdC++. В clang ++, даже если я использую '-std = C++ 98', код все еще не компилируется. – vsoftco

2

Я думаю, что это допустимо для if (std::cout) ..., не допуская неявного преобразования в bool, или что-то в этом роде.

+0

Это не дает ответа на вопрос. Чтобы критиковать или просить разъяснения у автора, оставьте комментарий ниже их сообщения. –

+0

@ A.L: Какого черта? – Mehrdad

+0

IIRC, этот ответ появился в очереди просмотра * низкого качества. Я категоризировал его как * не ответ * из-за использования * я думаю * и * что-то вроде этого *, для меня это выглядело как комментарий, а не ответ. Но я не знаю C++, извините, если это правильный ответ, и если было ошибкой его отмечать. –

4

Отвечая только на последующие действия, так как ответ nicebyte идеально подходит для исходного вопроса.

Скорее всего, ваш gcc настроен на использование libstdC++ (который еще не изменил оператор из-за того, что он был изменением ABI), и ваш clang настроен на использование libC++ (который был с самого начала предназначенным как стандартная библиотека C++ 11 и не совсем совместима в режиме C++ 98 - она ​​предоставляет оператор преобразования bool, который явствен в C++ 11).

+1

Хорошо, имеет смысл, спасибо за разъяснение. – vsoftco