Reputation: 313
While implementing a simple logger
struct DebugOutput {
DebugOutput(std::ostream& out = std::cerr) : m_Out(out) {}
template<typename T>
inline DebugOutput& operator <<(T&& value) {
m_Out << value;
return *this;
}
private:
std::ostream& m_Out;
};
I found out std::endl
wouldn't be captured by the universal reference.
DebugOutput dbg;
dgb << std::endl;
I found this this post which explains you need to add an overloaded function within the structure which takes specifically the function pointer signature, ie :
typedef std::ostream& (*StandardEndLine)(std::ostream&);
inline DebugOutput& operator<<(StandardEndLine manip) {
return *this;
}
Why the function pointer is not captured by the universal reference ? Isn't it a type as int
or void*
?
Upvotes: 12
Views: 654
Reputation: 20533
A function (pointer) can be bound to a universal reference. Example:
void f(int) {}
template <typename T>
void foo(T&&) {}
foo(f); // OK
However, an overloaded function cannot. That is, if you add a second overload of f
, say,
void f(double) {}
the the call foo(f)
will fail.
Put yourself on the compiler shoes. It's required to pass f
to foo
and there are two functions named f
each of which has a different type. If we inform the type, then the compiler can unambigously choose the correct f
. For instance,
foo(static_cast<void (*)(int)>(f));
compiles fine and will pass void f(int)
(after function-to-pointer conversion) to foo
.
However, we are not informing the type. We're rather asking the compiler to deduce it.
Similarly to f
, the same argument applies to std::endl
because this is a function template and, therefore, the name std::endl
represents a set of functions, all with the same name but different types.
Now, you can see that the cause of the error is the fact that we provide an overload set and ask for type deduction. Hence, this is not particular to universal references.
std::cout << std::endl
works because basic_ostream::operator <<
is not a template and doesn't try to deduce the type of the passed argument. It's a function that takes one particular type of std::endl
.
Upvotes: 13