简体   繁体   中英

Why Is Ampersand Necessary For Referencing The Call Operator

I thought the C++ specification says an ampersand in front of a function is not necessary when referencing a function, ie

void bar();
void foo(void(*bar)());

foo(bar);
foo(&bar);  // Same as above.

However, I found a case where this is not true. I was trying to do template specialization over lambda (of a single argument only) so that I could access the types of both the return argument and the input argument of a lambda.

// The ampersand in front of 'Fn::operator()' is necessary to make
// this code work.
template <typename Lambda>
struct Signature : public Signature<decltype(&Fn::operator())> {};

template <typename ClassT, typename RetT, typename ArgT>
struct Signature<RetT(ClassT::*)(ArgT) const> {
  using ReturnType = RetT;
  using ArgumentType = ArgT;
};

Without the ampersand, clang complains

error: call to non-static member function without an object argument
struct Signature : public Signature<decltype(Fn::operator())> {};
                                             ~~~~^~~~~~~~

I got the code to work, but I would like to understand why it works. Why is the ampersand necessary here?

To take the address of a member function, you must always prefix it with & (ampersand). This is true not only for templates and/or lambdas, but any member function in C++.

As for why , we can only speculate. But this is how C++ has always been. Perhaps C compatibility is the only reason omitting the & for free functions is allowed.

Pointers to functions and pointers to member functions are different beasts. While functions decay to pointers to functions, the same is not true for member functions or member objects. While there is a standard function to pointer conversion there is nothing similar for member functions or member objects. When you want to get a pointer to member you always need to use an & .

I don't know the exact reasoning but I suspect that the address-of operator was required to avoid mistakes which sometimes show up with functions, eg:

int f();
// ...
if (f) { // always true
}

While the implicit conversion from functions to function pointers couldn't be removed without breaking C compatibility, there was no similar concern when members and pointer to members were introduced.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM