Почему создается экземпляр шаблона оператора потока вместо глобального перегруженного оператора? - PullRequest
3 голосов
/ 18 февраля 2012

Предполагая следующий код.Есть класс MyStream, у которого шаблон перегружен оператором <<.Также есть глобально перегруженный оператор MyStream & operator << (MyStream &, const MyClass &).Непонятно, как генерировать (компилятором) разные методы для двух почти идентичных ситуаций (см. Основную часть функции main ()).Я предполагал, что глобальный оператор должен использоваться в обоих случаях, но это не так.Почему так? </p>

#include <iostream>

class MyStream;
class MyClass;
MyStream& operator << (MyStream& stream, const MyClass&);

class MyStream
{
public:
    template <typename T>
    MyStream& operator << (const T&)
    {
        std::cout << __FUNCTION__ << " " << typeid(T).name() << std::endl;
        return *this;
    }
};

class MyClass
{
};

MyStream& operator << (MyStream& stream, const MyClass&)
{
    std::cout << __FUNCTION__ << " " << typeid(MyClass).name() << std::endl;
    return stream;
}

int main(int, char**)
{
    // 1. Used globally defined operator for MyClass
    MyStream() << int() << MyClass();
    std::cout << std::endl;

    // 2. Template instantiation
    MyStream() << MyClass();

    std::cin.get();
    return 0;
}

Вывод программы, скомпилированной с помощью компиляторов Microsift Visual C ++ 9.0 (x86):

MyStream::operator << int
operator << class MyClass

MyStream::operator << class MyClass

1 Ответ

5 голосов
/ 18 февраля 2012
// 2. Template instantiation
 MyStream() << MyClass();

В этом случае выражение MyStream() создает временный объект ( rvalue ), который не может быть привязан к неконстантной ссылке, поэтому компилятор выбирает шаблон функции-члена, потому что для вызова В свободной функции временный объект должен быть передан в качестве первого аргумента функции, что здесь невозможно, так как тип первого параметра свободной функции является неконстантной ссылкой. Так MyStream << MyClass() вызывает функцию-член.

Но когда вы пишете это:

// 1. Used globally defined operator for MyClass
MyStream() << int() << MyClass();

Сначала вызывается функция-член, передающая int(), а функция-член возвращает объект типа MyStream&, который теперь может быть передан свободной функции в качестве первого аргумента (так как нет больше a rvalue , теперь это lvalue ), затем он вызывает свободную функцию, передавая объект типа MyStream& в качестве первого аргумента и MyClass() в качестве второго аргумента.

Это интересно, и здесь происходит нечто подобное:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...