2016-07-10 1 views
1

У меня есть класс, который очень похож на (версия C++ 11) std::ostream, к которому я могу передавать много разных (несвязанных) типов.Является ли систематическая перегрузка для ссылок на r-значение хорошим рисунком?

class mystream{...some implementation...};

Типичная функция для определения является

mystream& operator<<(mystream& ms, type1 const& t1){...}

mystream& operator<<(mystream& ms, type2 const& t2){...}

т.д.

Однако, (так же, как с 11 C++ в потоке) Я хотел бы к потоку-на-строительстве. Например:

mystream{} << t1;

Чтобы быть в состоянии сделать это, я перегрузить на ссылках л-значение для каждого типа:

mystream& operator<<(mystream&& ms, type1 const& t1){ 
    return ms << t1; // this calls the l-value version 
} 

код не является сложным, но это повторяется, потому что Я должен сделать это для всех типов. Из-за природы этого класса имеет смысл использовать ссылки и ссылки на l-значение.

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

Вторичный вопрос: Конечно, я мог бы сделать некоторую магию шаблонов, чтобы при необходимости принимать ссылки на l-значение, но опять же я не знаю, является ли это рекомендуемым путем.

Тернарный вопрос: должна ли функция вернуть mystream& (например, выше) или mystream&&.


Это пример кода:

class A{}; 
class B{}; 

class mystream{}; 

mystream& operator<<(mystream& ms, A const& a){return ms;} // (1) 
mystream& operator<<(mystream& ms, B const& b){return ms;} // (2) 

mystream& operator<<(mystream&& ms, A const& a){return ms; /*ms << a;*/} // (3) 
mystream& operator<<(mystream&& ms, B const& b){return ms; /*ms << a;*/} // (4) 

int main(){ 

    mystream ms; 
    ms << A{}; 
    ms << B{}; 

    mystream{} << A{}; // ok only if line (3) is defined 
    mystream{} << B{}; // ok only if line (4) is defined 

} 

Если я комментирую линия (3) сообщение об ошибке

fatal error: invalid operands to binary expression ('mystream' and 'A') 
     mystream{} << A{}; // ok only if line (3) is defined 
     ~~~~~~~~~~^~~~ 
././random.hpp:146:11: note: candidate function not viable: expects an l-value for 1st argument 
mystream& operator<<(mystream& ms, A const& a){return ms;} // (1) 

Если я комментирую линия (1) обратное происходит

fatal error: invalid operands to binary expression ('mystream' and 'A') 
     ms << A{}; 
     ~~^~~~ 
././random.hpp:149:11: note: candidate function not viable: no known conversion from 'mystream' to 'mystream &&' for 1st argument 
mystream& operator<<(mystream&& ms, A const& a){return ms; /*ms << a;*/} // (3) 

ответ

2

C++ определяет одну функцию шаблон, который принимает исходное значение rstream:

template< class CharT, class Traits, class T > 
basic_ostream< CharT, Traits >& operator<<(basic_ostream<CharT,Traits>&& os, 
              const T& value); 

Он вызывает соответствующий оператор ввода. Соответственно, вы должны определить только

template <typename X> 
mystream& operator<< (mystream&& ms, const X& x) 
{ 
    ms << x; 
    return ms; 
} 
+0

Это также верно для конкретных классов 'std :: o? Stream'? (например, 'std :: ofstream'). Во всяком случае, я думаю, что 'ms << x;' в вашем коде будет ссылаться на ссылку l-value для конкретного класса. Кроме того, это не сработает для меня, потому что этот вызов не будет работать. 'mystream ms {}; ms << t1; '. – alfC

+0

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

+0

Да, но полагается на наличие l-value версии функции в производном конкретном классе.Мой вопрос не включает в себя наследование или базовые классы. Я добавил пример кода, чтобы показать, почему, по-видимому, необходимо иметь две версии. – alfC

Смежные вопросы