перегрузка оператора‹‹ для типа члена в классе шаблона в C++

В приведенном ниже коде у меня есть класс шаблона с типом члена (элемент структуры). Я хочу перегрузить оператор‹‹ для этого типа члена. Однако код не будет компилироваться.

Я был бы признателен, если бы кто-нибудь мог указать, где я ошибаюсь?

include <iostream>
using namespace std;

// fwd decl
template<class T> class CC;

// operator<< overload template for member type CC<T>::Element
template<class T>
ostream& operator<<(ostream& os, const typename CC<T>::Element& elm) {
    return os << elm.val1 << "/" << elm.val2;
}

template<class T>
class CC
{
public:
    struct Element {    // type member
        int val1;
        int val2;
    };

    template<typename U>
    friend ostream& operator<<(ostream& os, const typename CC<U>::Element& elm);
};

int main() {
    CC<int>::Element elm{0,0};
    cout << elm << endl;     // does not compile due to this!
}

person Kemal    schedule 08.06.2016    source источник


Ответы (2)


Аргументы шаблона не могут быть выведены из вложенной сущности (краткое объяснение: тип может быть одинаковым для разных экземпляров шаблона). То есть декларация

template<typename U>
ostream& operator<<(ostream& os, const typename CC<U>::Element& elm);

независимо от того, для friend или нет, никогда не рассматривается, потому что тип U не может быть выведен. Вы можете решить проблему, сделав оператор friend не шаблонным:

// ...
friend ostream& operator<<(ostream& os, const Element& elm) { ... }
// or
friend ostream& operator<<(ostream& os, const CC<T>::Element& elm) { ... }
// ...

Однако функция должна быть реализована в ее объявлении.

person Dietmar Kühl    schedule 08.06.2016
comment
Спасибо, что нашли время. Я попробовал оба ваших предложения, но код все еще не компилируется. Я получаю эту ошибку: неопределенная ссылка на `operator‹‹(std::ostream&, CC‹int›::Element const&)' - person Kemal; 08.06.2016
comment
Сотрите мой предыдущий комментарий. Моя ошибка. Я должен написать реализацию, как вы упомянули, чего я не сделал. Спасибо еще раз. - person Kemal; 08.06.2016

Ваша проблема в том, что в следующем коде

 ostream& operator<<(ostream& os, const typename CC<T>::Element& elm) {

Element находится в невыведенном контексте. В результате аргумент шаблона не может быть выведен. И поскольку вызов operator<< с явным аргументом шаблона был бы действительно уродлив (если вообще возможен), я предлагаю изменить общий шаблон кодирования.

Например, вы можете сделать elm выводимым аргументом шаблона, например

template<typename E>
friend ostream& operator<<(ostream& os, const E& elm);

А затем извлеките фактические U из E, используя специализированную структуру.

person SergeyA    schedule 08.06.2016
comment
Обратите внимание, что эта функция templates концептуально объявляет неограниченный шаблон. Поскольку он находится в другом классе, его не будут искать во многих контекстах, и его можно будет найти только с помощью ADL. Я бы по-прежнему избегал использования неограниченных шаблонов при реализации точки настройки. - person Dietmar Kühl; 08.06.2016
comment
@DietmarKühl, я, конечно, понимаю вашу точку зрения, и я вовсе не спорю об этом. Ваше решение лучше - поэтому я проголосовал за него :) - person SergeyA; 08.06.2016