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*
?
Pass-by-pointer means to pass a pointer argument in the calling function to the corresponding formal parameter of the called function. The called function can modify the value of the variable to which the pointer argument points. When you use pass-by-pointer, a copy of the pointer is passed to the function.
Generally no. The types have to be related. It is possible to use reinterpret_cast to cast a pointer from one type to another, but unless those pointers can be converted legally using a static_cast , the reinterpret_cast is invalid.
A pointer to a function points to the address of the executable code of the function. You can use pointers to call functions and to pass functions as arguments to other functions. You cannot perform pointer arithmetic on pointers to functions.
No. You must not because free(ptr) is used only when pointer ptr is previously returned by any of malloc family functions. Passing free a pointer to any other object (like a variable or array element) causes undefined behaviour.
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With