Порядок разрешения перегрузки оператора, включающего временные файлы

Рассмотрите следующий минимальный пример:

#include <iostream>

using namespace std;

class myostream : public ostream {
    public:
        myostream(ostream const &other) :
            ostream(other.rdbuf())
        { }
};

int main() {
    cout << "hello world" << endl;

    myostream s(cout);
    s << "hello world" << endl;

    myostream(cout) << "hello world" << endl;
}

Вывод, и на g ++ и на Visual C++,

hello world
hello world
0x4012a4

Версия, которая пишет во временный объект, myostream(cout), кажется, предпочитает членский оператор ostream::operator<<(void *), вместо бесплатного оператора operator<<(ostream &, char *). Это, кажется, имеет значение, имеет ли объект имя.

Почему это происходит? И как я предотвращаю это поведение?

Править: То, почему это происходит, теперь ясно из различных ответов. Относительно того, как предотвратить это, следующее кажется обращением:

class myostream : public ostream {
    public:
        // ...
        myostream &operator<<(char const *str) {
            std::operator<<(*this, str);
            return *this;
        }
};

Однако это приводит ко всем видам неоднозначностей.

11
задан Thomas 12 February 2010 в 08:55
поделиться

5 ответов

rvalues не могут быть связаны с неконстантной ссылкой. Поэтому в вашем примере временный тип ostream не может быть первым аргументом свободного operator<<(std::ostream&, char const*), а используется член operator<<(void*).

Если вам это нужно, вы можете добавить вызов типа

myostream(cout).flush() << "foo";

который преобразует rvalue в ссылку.

Обратите внимание, что в C++0X введение rvalue reference позволит обеспечить перегрузку operator<<, принимающего rvalue references в качестве параметра, что решит первопричину проблемы.

6
ответ дан 3 December 2019 в 07:37
поделиться

Если у объекта нет имени (т.е. он временный), его нельзя привязать к неконстантной ссылке. В частности, он не может быть связан с первым параметром:

operator<<(ostream &, char *)
7
ответ дан 3 December 2019 в 07:37
поделиться

Я только что понял часть ответа. Временное значение не является lvalue, поэтому его нельзя использовать в качестве аргумента типа ostream & .

Остается вопрос «как я могу это сделать?» ...

3
ответ дан 3 December 2019 в 07:37
поделиться

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

Временный объект находится в стеке, обычно для передачи другой функции или для вызова одной операции. Итак, если вы вызовете для него свободный оператор:

operator << (myostream (cout))

Он уничтожается в конце этой операции, и второй оператор «<<» для добавления endl будет ссылаться на недопустимый объект. Значение, возвращаемое свободным оператором «<<», будет ссылкой на разрушенный временный объект. Спецификация C ++, вероятно, определяет правила для свободных операторов, чтобы этот сценарий не расстраивал и не сбивал с толку программистов на C ++.

Теперь, в случае оператора-члена «<< (void *)» для временного объекта, возвращаемое значение - это сам объект, который все еще находится в стеке и не уничтожен, поэтому компилятор знает, что его нельзя разрушать. но чтобы передать его следующему оператору-члену, который принимает endl. Цепочка операторов на временных библиотеках - полезная функция для сжатого кода C ++, поэтому я уверен, что разработчики спецификации C ++ учли ее и реализовали компилятор для ее поддержки намеренно.

править

Некоторые говорили, что это связано с неконстантной ссылкой. Этот код компилируется:

#include <iostream>
using namespace std;
class myostream : public ostream { 
    public: 
        myostream(ostream const &other) : 
            ostream(other.rdbuf()) 
        { } 
            ~myostream() { cout << " destructing "; }
    }; 
int _tmain(int argc, _TCHAR* argv[])
{
    basic_ostream<char>& result = std::operator << (myostream(cout), "This works");
    std::operator << (result, "illegal");
         return 0;
}

И возвращает

  This works destructing illegal
-1
ответ дан 3 December 2019 в 07:37
поделиться

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

myostream operator<<(myostream stream, char const *str) {
    std::operator<<(stream, str);
    return stream;
}

Это возможно только потому, что myostream имеет конструктор копирования. (Внутри он поддерживается std::stringbuf с реф-счетом)

.
1
ответ дан 3 December 2019 в 07:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: