Параметризованные пользовательские манипуляторы потока — зачем перегружать «оператор<

#c #iostream #manipulators

Вопрос:

Я пытаюсь реализовать параметризованный манипулятор потоком для определенного набора данных. Я делаю это простым способом, как рекомендовано:

 class print_my_data
{
private:
    . . .

public:
    print_my_data(. . .) { . . . }

    ostreamamp; operator()(std::ostreamamp; out)
    {
        return out << . . . << endl;
    }
};

ostreamamp; operator<<(ostreamamp; out, print_my_data md) // <=== MY QUESTION BELOW IS ABOUT THIS
{
    return md(out);
}

 

Использование:

 clog << print_my_data(. . .) << endl;
 

Это прекрасно работает; но я действительно не понимаю, почему это не работает, если я не определю operator<< ! Почему он не вызовет ту же перегруженную функцию, что и для endl ?? (т. Е. в качестве объекта, который может быть применен к потоку через operator() )

Ответ №1:

Перегрузка, которую вы ищете, определена только для указателей функций.

 basic_ostreamamp; operator<<(
   std::basic_ostream<CharT,Traits>amp; (*func)(std::basic_ostream<CharT,Traits>amp;) );
 

Ваш print_my_data класс является вызываемым объектом (функтором, в терминах C ). Но это не указатель на функцию. С другой стороны, endl является функцией и, следовательно, имеет указатель на функцию (на самом деле, это одна из немногих функций в стандартной библиотеке C , у которой есть адрес)

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

 basic_ostreamamp; operator<<(
   std::function<std::basic_ostream<CharT,Traits>amp;(std::basic_ostream<CharT,Traits>amp;)> func);
 

Но, увы, его не было рядом, когда были написаны операторы ввода-вывода. std::function Как и понятия, если уж на то пошло. И используя SFINAE для объявления

 template <typename F>
basic_ostreamamp; operator<<(
   F func);
 

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

Комментарии:

1. В любом случае, ни указатель на функцию print_my_data , ни a не являются std::function , и поэтому перегрузка также не будет выбрана.