Правильно объявленный шаблонный оператор << (basic_ostream <charT, traits>, myClass <T>) в качестве друга

0

Я пытаюсь улучшить свое понимание шаблонов. В качестве теста я хотел бы перегрузить operator<< потока operator<< чтобы он работал на шаблоном классе вместе с (templated) basic_ostream из STL. Вот минимальный пример:

#include <iostream>

using namespace std;

//Forward declarations
template< typename T >
class Container;
template< typename T, typename charT, typename traits >
basic_ostream< charT, traits >& 
    operator<<( basic_ostream< charT, traits >& out, 
                               const Container< T >& a_container ); 

//Definitions
template< typename T >
class Container
{
public:
    Container( T a_value ): value( a_value ){}

private:
    T value;

    template< typename charT, typename traits >
    friend basic_ostream< charT, traits >& 
        operator<<( basic_ostream< charT, traits >& out, 
                    const Container< T >& a_container );
};

template< typename T, typename charT, typename traits >
basic_ostream< charT, traits >& 
    operator<<( basic_ostream< charT, traits >& out, 
                const Container< T >& a_container )
{
    out << a_container.value;
    return out;
}

//Main
int main( void )
{
    Container< int > my_container( 42 );

    cout << my_container;

    return 0;
}

Однако, когда я пытаюсь скомпилировать этот код, компоновщик не может найти перегруженную функцию:

/home/Ae6PGM/cc5xj2iM.o: In function 'main':
prog.cpp:(.text.startup+0x21): undefined reference to 'std::basic_ostream<char,
std::char_traits<char> >& operator<< <char, std::char_traits<char> >
(std::basic_ostream<char,     std::char_traits<char> >&, Container<int> const&)'
collect2: error: ld returned 1 exit status

Я могу исправить эту ошибку, если я делаю каждый экземпляр экземпляра моего перегруженного operator<< другом, но это кажется более правильным, если только экземпляры, соответствующие типу контейнера, являются друзьями. Вот ссылка на рабочий, но неверный вариант: http://ideone.com/DNQzlB.

Другой альтернативой является определение функции внутри объявления класса, но я хотел бы избежать этого, если это возможно.

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

Благодаря,

Андрей

  • 0
    Я начинаю думать, что это невозможно, так как он будет опираться на частично специализированный шаблон функции, который не поддерживается в C ++. Это правильно?
  • 0
    Я думаю, что ответ здесь может помочь: stackoverflow.com/questions/1458752/template-friendship
Показать ещё 1 комментарий
Теги:
c++11
templates
language-lawyer

2 ответа

0
Лучший ответ

Исходное объявление вашего шаблона взяло три параметра шаблона { T, charT, traits } но в объявлении friend только 2 { charT, traits }. Вы получаете неопределенную ссылку, потому что компилятор рассматривает их как две отдельные функции, одна из которых не определена.

Вам нужно дать ему третий аргумент шаблона:

template< typename T2, typename charT, typename traits >
    friend basic_ostream< charT, traits >& 
        operator<< ( basic_ostream< charT, traits >& out, 
                    const Container< T2 >& a_container );
  • 0
    Это позволит скомпилировать и связать код, но сделает каждый экземпляр функции другом. Даже в случаях, когда тип T2 функции не соответствует типу T контейнера. Это разумный обходной путь на практике, но я хотел бы понять, есть ли более правильный способ сделать это.
  • 0
    @ andrew.punnett Это правильный способ сделать это. Однако становится еще сложнее, если вы хотите ограничить его одним определенным аргументом шаблона.
Показать ещё 12 комментариев
0

Спасибо, что задали этот вопрос. Я узнал совсем немного, просмотрев его.

Тем не менее, я думаю, я понимаю, что вы пытаетесь спросить. Если я правильно вас понимаю, вы пытаетесь внедрить и контролировать неявное создание экземпляра с помощью шаблона функции.

Хотя приведенный здесь пример перегрузки operator<<, механизм, лежащий в основе этого общего программирования с использованием шаблона, одинаковый для реализации шаблона функции.

Когда вы указываете cout << my_container, то, что вы создаете, является перегруженным operator<<. Но если вы хотите создать экземпляр объекта без шаблона, вам придется изменить то, что вы пытаетесь прочитать.

Поскольку значение элемента данных класса является закрытым, вы можете использовать указатель, чтобы явно указать на этот элемент данных, и использовать этот указатель для создания экземпляра объекта без шаблона. Взгляните на следующий пример:
int* private_value = (int*)&my_container;
*private_value должно позволить вам получить доступ к частному члену, несмотря на инкапсуляцию.

Если вы хотите повысить безопасность членов данных, то для предотвращения такой реализации необходимо более глубокое инкапсулирование.

Вывод аргумента шаблона может быть достигнут (если это то, что вы ищете), возможно, включая функцию get() и доступ к value, тем самым создавая экземпляр объекта без шаблона.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню