Std:: endl неизвестного типа при перегрузке оператора <<
I перегруженный оператор < <
template <Typename T>
UIStream& operator<<(const T);
UIStream my_stream;
my_stream << 10 << " heads";
Работает, но:
my_stream << endl;
Дает ошибку компиляции:
ошибка C2678: двоичная '< <: оператор не найден, который принимает левый операнд типа UIStream (или нет приемлемого преобразования)
Какова работа для работы my_stream << endl
?
Ответы
Ответ 1
std::endl
- это функция, а std::cout
использует ее, реализуя operator<<
, чтобы взять указатель на функцию с той же сигнатурой, что и std::endl
.
В нем он вызывает функцию и пересылает возвращаемое значение.
Вот пример кода:
#include <iostream>
struct MyStream
{
template <typename T>
MyStream& operator<<(const T& x)
{
std::cout << x;
return *this;
}
// function that takes a custom stream, and returns it
typedef MyStream& (*MyStreamManipulator)(MyStream&);
// take in a function with the custom signature
MyStream& operator<<(MyStreamManipulator manip)
{
// call the function, and return it value
return manip(*this);
}
// define the custom endl for this stream.
// note how it matches the `MyStreamManipulator`
// function signature
static MyStream& endl(MyStream& stream)
{
// print a new line
std::cout << std::endl;
// do other stuff with the stream
// std::cout, for example, will flush the stream
stream << "Called MyStream::endl!" << std::endl;
return stream;
}
// this is the type of std::cout
typedef std::basic_ostream<char, std::char_traits<char> > CoutType;
// this is the function signature of std::endl
typedef CoutType& (*StandardEndLine)(CoutType&);
// define an operator<< to take in std::endl
MyStream& operator<<(StandardEndLine manip)
{
// call the function, but we cannot return it value
manip(std::cout);
return *this;
}
};
int main(void)
{
MyStream stream;
stream << 10 << " faces.";
stream << MyStream::endl;
stream << std::endl;
return 0;
}
Надеюсь, это даст вам лучшее представление о том, как это работает.
Ответ 2
Проблема заключается в том, что std::endl
является шаблоном функции, так как ваш оператор <<
является. Поэтому, когда вы пишете:
my_stream << endl;
вам понравится компилятору вывести параметры шаблона для оператора
а также для endl
. Это невозможно.
Итак, вам нужно написать дополнительные, без шаблонов, перегрузки оператора <<
в
работа с манипуляторами. Их прототип будет выглядеть так:
UIStream& operator<<(UIStream& os, std::ostream& (*pf)(std::ostream&));
(есть еще два, заменив std::ostream
на std::basic_ios<char>
и
std::ios_base
, который вы также должны предоставить, если хотите разрешить все
манипуляторы), и их реализация будет очень похожа на
ваши шаблоны. На самом деле, так что вы можете использовать свой шаблон для
реализация такая:
typedef std::ostream& (*ostream_manipulator)(std::ostream&);
UIStream& operator<<(UIStream& os, ostream_manipulator pf)
{
return operator<< <ostream_manipulator> (os, pf);
}
Последнее замечание, часто пишущее пользовательский streambuf
, часто является лучшим способом
достигните того, к чему пытаетесь добиться применения техники, которую вы используете.
Ответ 3
Я сделал это, чтобы решить свою проблему, вот часть моего кода:
template<typename T>
CFileLogger &operator <<(const T value)
{
(*this).logFile << value;
return *this;
}
CFileLogger &operator <<(std::ostream& (*os)(std::ostream&))
{
(*this).logFile << os;
return *this;
}
main.cpp
int main(){
CFileLogger log();
log << "[WARNINGS] " << 10 << std::endl;
log << "[ERRORS] " << 2 << std::endl;
...
}
Я получил ссылку здесь http://www.cplusplus.com/forum/general/49590/
Надеюсь, это поможет кому-то.
Ответ 4
См. здесь для улучшения способов расширения IOStreams. (Немного устаревший и адаптированный для VC 6, поэтому вам придется брать его с солью)
Дело в том, что для работы функторов (и endl, которые оба выхода "\n" и flushes являются функторами), вам необходимо реализовать полный интерфейс ostream.
Ответ 5
Потоки std
не предназначены для подкласса, поскольку у них нет виртуальных методов, поэтому я не думаю, что вы слишком забудете это. Вы можете попытаться объединить std:: ostream для выполнения работы.
Чтобы выполнить работу endl
, вам нужно реализовать версию operator<<
, которая принимает указатель на функцию, так как обрабатываются манипуляторы, такие как endl
i.e.
UStream& operator<<( UStream&, UStream& (*f)( UStream& ) );
или
UStream& UStream::operator<<( UStream& (*f)( UStream& ) );
Теперь std::endl
- это функция, которая берет и возвращает ссылку на std:: basic_ostream, поэтому она не будет работать непосредственно с вашим потоком, поэтому вам нужно будет сделать свою собственную версию, которая будет звонить на std::endl
версии в вашем агрегированном std::iostream
.
Изменить: выглядит лучше GMan ответ лучше. Он также работает std::endl
!
Ответ 6
В дополнение к принятому ответу, с С++ 11 можно перегрузить operator<<
для типа:
decltype(std::endl<char, std::char_traits<char>>)