1

I want to create a function that takes in anything that the << operator for std::cout can handle. I have an example that breaks.

#include <iostream>

template <typename T>
void my_print(const T &t) {
  std::cout << t;
}

int main() {
  my_print("hello\n"); // works
  my_print(4); // works
  my_print(std::endl); // compiler error
  return 0;
}

It also fails if I change to void my_print(T t). The compiler error is

error: no matching function for call to 'my_print(<unresolved overloaded function type>)'
note: candidate is
note: template<class T> void my_print(const T&)

Why can't the compiler resolve it when it sees that the argument t is being put into cout?

Is there any good way to fix this or do I have to manually provide the additional << cases, e.g. void my_print(ostream& (*pf)(ostream&));

EDIT: I know endl is a function. Is the answer then that function types are not accepted as templates? Like I can't have [T = ostream& (*)(ostream&)]?

Nick
  • 2,821
  • 5
  • 30
  • 35
  • possible duplicate of [std::endl is of unknown type when overloading operator<<](http://stackoverflow.com/questions/1134388/stdendl-is-of-unknown-type-when-overloading-operator) – Rubens Apr 22 '13 at 23:54
  • 1
    It's because endl *isn't* a function... – Kerrek SB Apr 22 '13 at 23:59
  • @KerrekSB Huh? `ostream& operator<< (ostream& (*pf)(ostream&))` is what is invoked by `cout << endl`. This seems to indicate that `endl` is a function taking and returning an `ostream&`. – Nick Apr 23 '13 at 00:03
  • @Nick std::endl is indeed a function. – Thibaut Apr 23 '13 at 00:12
  • @Nick: It's a function *template* which can be instantiated to match that `ostream` overload. But that's not the same as being a function, as you've just experienced yourself. – Kerrek SB Apr 23 '13 at 08:01
  • It's not a _single_ function, most importantly (you have the same problem with non-templated overload sets). – MSalters Apr 23 '13 at 08:58

1 Answers1

0

std::endl is actually a function template. You can read the full documentation here or here. It is defined as:

template< class CharT, class Traits >
std::basic_ostream<charT,traits>& endl( std::basic_ostream<CharT, Traits>& os );

Edit: You can achieve what you want using this solution (which I vaguely adapted from here)

#include <iostream>

// handles the other types
template <typename T>
void my_print(const T &t) {
  std::cout << t;
}

// alias a few things to make the prototypes readable
typedef std::basic_ostream<char, std::char_traits<char> > CoutType;
typedef CoutType& (*StandardEndLine)(CoutType&);

int main() {
  my_print("hello\n"); // works
  my_print(4); // works
  my_print((StandardEndLine)std::endl); // <- NOTE: there is an explicit cast
  return 0;
}
Community
  • 1
  • 1
Thibaut
  • 2,400
  • 1
  • 16
  • 28