Как в явном виде вызвать шаблонную перегрузку оператора <<? - PullRequest
2 голосов
/ 08 ноября 2019

Рассмотрим следующий пример кода для перегрузки operator<< для class A:

#include <iostream>
class A {
    template <typename T>
    friend A &operator<<(A &a, const T &t)
    {
         std::cout << t << std::endl;
         return a;
    }
    friend A &operator<<(A &a, const std::string &t)
    {
         return operator<<<std::string>(a, t + "x");
    }
};

Мое намерение состоит в том, чтобы второй оператор явно вызывал первый.

Однако,в g ++ 7.4 это завершается с

В функции 'A & operator << (A &, const string &)': <br>error: 'operator <<' не определено <br>return operator <<(а, т + "х");<br> ^ ~
ошибка: ожидаемое первичное выражение перед маркером '>'
оператор возврата <<(а, т + "х");<br> ^

Однако я не понимаю, почему это не должно компилироваться.

Вот код в кресте.

Ответы [ 3 ]

2 голосов
/ 08 ноября 2019

Функции друзей в классе не доступны для любой области видимости. Раньше инъекция друга была чем-то особенным (до изобретения ADL), но теперь нет способа вызвать их, кроме как с помощью ADL, если вы не объявите их заранее. В этом случае обходным путем является предварительное объявление функции шаблона вне класса.

class A;

template <typename T>
A &operator<<(A &a, const T &t);
1 голос
/ 08 ноября 2019

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

template <> friend A& operator<< <std::string>(A &a, const std::string &t)
{
    // Print in here some how. It's not exactly clear to me how you intend to
    // do this, as doing something like a << t will create infinite recursion

    // finally, return a
    return a;
}

Другой вариант - переключить порядок функций, создав шаблонную функцию после , когда вы создадите свою первую функцию:

friend A &operator<<(A &a, const std::string &t)
{
    // Again, still not sure what you want to do here
    // I just want to stress again though, don't do something
    // like a << t, or operator<<(a,t)
    // That will crash hard and fast, as there is no way to resolve
    // it. It will create infinite recursion

    return a;
}

template <typename T>
friend A &operator<<(A &a, const T &t)
{
     std::cout << t << std::endl;
     return a;
}

Мое намерение состоит в том, чтобы второй оператор явно вызывал первый.

Итак, во-первых, вам действительно понадобится первый вариант в этом случае.

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

operator<< <SomeType>(a,t);

Имейте в виду, что t необходимо будет неявно преобразовать в SomeType. Иначе, SomeType необходимо создать, вызвав его конструктор:

operator<< <SomeType>(a,SomeType(/* parameters to construct a SomeType ... */));

Примечание: выполнение чего-то вроде operator<< <SomeType>(a,t + "x") всегда станет бесконечно рекурсивным и в конечном итоге приведет к краху. Это потому, что t + "x" всегда является std::string. Это означает, что компилятор всегда будет бесконечно вызывать эту перегрузку функции до тех пор, пока он окончательно не завершится из-за переполнения стека . Так что не делай этого.

1 голос
/ 08 ноября 2019

Вызов функции вместо вызова оператора.

#include <iostream>
class A {
    template <typename T>
    static A &print(A &a, const T &t)
    {
        std::cout << t << std::endl;
        return a;
    }

    template <typename T>
    friend A &operator<<(A &a, const T &t)
    {
         return print(a, t);
    }
    friend A &operator<<(A &a, const std::string &t)
    {
         return print(a, t + "x");
    }
};
...