Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why a function pointer is not captured by universal reference?

Tags:

c++

c++11

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* ?

like image 695
Guillaume Chatelet Avatar asked Sep 27 '13 09:09

Guillaume Chatelet


People also ask

What happens when pointer is passed to a function?

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.

Can a pointer refer to any type?

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.

Can we have a pointer to a function?

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.

Do function pointers need to be freed?

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.


1 Answers

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.

like image 87
Cassio Neri Avatar answered Sep 22 '22 03:09

Cassio Neri