У меня есть класс, который очень похож на (версия 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)
Это также верно для конкретных классов 'std :: o? Stream'? (например, 'std :: ofstream'). Во всяком случае, я думаю, что 'ms << x;' в вашем коде будет ссылаться на ссылку l-value для конкретного класса. Кроме того, это не сработает для меня, потому что этот вызов не будет работать. 'mystream ms {}; ms << t1; '. – alfC
Он всегда возвращает ссылку на базовый класс. Если вы получаете ошибки компиляции, пожалуйста, укажите полный код и полные сообщения об ошибках. –
Да, но полагается на наличие l-value версии функции в производном конкретном классе.Мой вопрос не включает в себя наследование или базовые классы. Я добавил пример кода, чтобы показать, почему, по-видимому, необходимо иметь две версии. – alfC