Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is there only pointer to function instead of var of function?

In C/C++, we can declare/define a type of pointer to function, and then declare/define some variables of this type. But I think it is ambiguity.

For example:

typedef void ( *pFunc )();
// typedef void ( aFunc )();
void theFunc() {
   cout << "theFunc has been called successfully." << endl;
};

int main() {
   pFunc pf0 = theFunc;
   pFunc pf1 = &theFunc;

   pf0();
   ( *pf0 )();
   pf1();
   ( *pf1 )();
};

Theoretically, only pFunc pf1 = &theFunc; and (*pf1)(); are legal, but all of above can pass through compilation.

In Pascal syntax, we need to define vars of function or vars of pointer to a function respectively, and the meaning of them are different and much clearer(at least I think so)!

Moreover, we can't declare/define a var of function instead of a var of pointer to function! I tried follows and get failed.

typedef void ( aFunc )();
aFunc af0 = theFunc;

If with other types such as int/double, there are very strict syntax that restricts us to use them correctly. (If int* is not same as int, why is *pf0 is same as pf0?!)

So, Can I think it is a bug of C/C++ standard?

like image 814
Leon Avatar asked Nov 06 '22 15:11

Leon


1 Answers

Some declared types:

// decltype of theFunc is void ()
// decltype of &theFunc is void (*) ()
// decltype of *theFunc is void (&) ()

Now, concerning your code, since a function is implicitly convertible to a pointer to that function, we have:

using pFunc = void(*)();
using rFunc = void(&)();

pFunc p_fct = &theFunc; // no conversion
pFunc p_fct = theFunc;  // conversion lvalue to pointer
pFunc p_fct = *theFunc; // conversion lvalue reference to pointer

rFunc r_fct = *theFunc; // no conversion
rFunc r_fct = theFunc;  // conversion lvalue to lvalue reference
rFunc r_fct = &theFunc; // ERROR: conversion pointer to lvalue reference not allowed

So far the conversions. Now, any object of type pFunc or rFunc is a callable object. Also, note that both (*p_fct) and (*r_fct) are of type rFunc. Therefore, you can call your function as described in the question:

p_fct();    // callable object of type pFunc
r_fct();    // callable object of type rFunc
(*p_fct)(); // callable object of type rFunc
(*r_fct)(); // callable object of type rFunc

Note that the following is equivalent to the above:

using Func = void ();
Func* p_fct = &theFunc; // no conversion
Func& r_fct = *theFunc; // no conversion
p_fct();                // callable of type Func* or pFunc
r_fct();                // callablel of type Func& or rFunc

EDIT To answer to the question: "why them was arranged in this way" from the below comment: functions cannot be copied (as explained in @JohnBurger's answer). This is why your code:

typedef void ( aFunc )();
aFunc af0 = theFunc;

doesn't work. As explained above, you can do the following though:

typedef void ( aFunc )();
aFunc* af0 = &theFunc; // or theFunc, or even *theFunc

Or you could do this:

auto myFct = theFunc;

But keep in mind that the decltype of myFct is still void (*)().

like image 119
mfnx Avatar answered Nov 15 '22 07:11

mfnx