8

What's the difference between

typedef void (&FunctionTypeR)();

vs

typedef void (FunctionType)();

Is the second also a reference to function? Is FunctionTypeR equivalent to FunctionType& when used as the type of an argument?

For

void foo(FunctionType bar)

Does the runtime makes a copy of the argument bar (a function) when foo is invoked?

Candy Chiu
  • 6,579
  • 9
  • 48
  • 69

1 Answers1

17

The difference is that you cannot create objects of function type, but you can create of objects of function pointer type, and function reference type.

That means if you've a function, say f() as:

 void f(){}

then here is what you can do, and what you cannot do:

FunctionType  fun1 = f; //error - cannot create object of function type
FunctionType *fun2 = f; //ok 
FunctionTypeR fun3 = f; //ok

Test code:

typedef void (&FunctionTypeR)();
typedef void FunctionType();

void f(){}

int main() {
        FunctionType  fun1 = f; //error - cannot create object of function type
        FunctionType *fun2 = f; //ok 
        FunctionTypeR fun3 = f; //ok
        return 0;
}

Now see the compilation error (and warnings):

 prog.cpp: In function ‘int main()’:
 prog.cpp:7: error: function ‘void fun1()’ is initialized like a variable
 prog.cpp:8: warning: unused variable ‘fun2’
 prog.cpp:9: warning: unused variable ‘fun3’

Online demo : http://ideone.com/hpTEv


However, if you use FunctionType (which is a function type) in a function parameter list as:

void foo(FunctionType bar);

then it's equivalent to

void foo(FunctionType * bar);

That means, no matter what you write, you can call the function using bar as:

   bar();  //ok
 (*bar)(); //ok 

That is, you can write this:

void h(FunctionType fun) { fun(); }
void g(FunctionType fun) { (*fun)(); }

Demo : http://ideone.com/kwUE9

This is due to function type to function pointer type adjustment; that is, the function type is adjusted to become a pointer to function type:

Function type     |  Function pointer type (adjusted type)
   void ()        |     void (*)()
   void (int)     |     void (*)(int)
   int  (int,int) |     int  (*)(int,int)
   ....           |      ... so on

The C++03 Standard says in §13.1/3,

Parameter declarations that differ only in that one is a function type and the other is a pointer to the same function type are equivalent. That is, the function type is adjusted to become a pointer to function type (8.3.5).

[Example:
    void h(int());
    void h(int (*)()); // redeclaration of h(int())
    void h(int x()) { } // definition of h(int())
    void h(int (*x)()) { } // ill-formed: redefinition of h(int())
]

And if you use `FunctionTypeR (which is a function reference type) as:

void foo(FunctionTypeR bar);

then it's equivalent to:

void foo(FunctionType * & bar);

And,

void h(FunctionTypeR fun) { fun(); }
void g(FunctionTypeR fun) { (*fun)(); }

Demo : http://ideone.com/SmtQv


Interesting part...

You can use FunctionType to declare a function (but not to define it).

For example,

struct A
{
   //member function declaration. 
    FunctionType f; //equivalent to : void f();
};

void A::f() //definition
{
  std::cout << "haha" << std::endl;
}

//forward declaration
FunctionType h; //equivalent to : void h();

int main() {
        A a;
        a.f(); //call member function
        h();   //call non-member function
}

void h() //definition goes below main()
{
   std::cout <<"hmmm.." << std::endl;
}

Demo : http://ideone.com/W4ED2

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • Does it mean void foo(FunctionType bar) is actually foo(FunctionType& bar)? which is equivalent to foo(FunctionTypeR bar)? – Candy Chiu Sep 06 '11 at 15:21
  • void 'foo(FunctionType bar)' is not an error. it compiles and runs. The error is 'FunctionType fun1 = f'; – Candy Chiu Sep 06 '11 at 15:33
  • Candy: I updated my answer. There was some confusion my mind as well. I clarified it now. – Nawaz Sep 06 '11 at 15:42
  • 1
    I'd say that the function type isn't entirely useless, because you can happily use it as a template parameter type, as is done by `std::function`. You can't have instances of that type, that's true, but the type itself is still useful. – Kerrek SB Sep 06 '11 at 15:47
  • @Kerrek: I didn't say function type is *entirely* useless. – Nawaz Sep 06 '11 at 15:49
  • @Kerrek: Although, I didn't say that `function type is entirely useless`, I changed the wordings of my answer. I hope it's better now. – Nawaz Sep 06 '11 at 15:52
  • @Nawaz What confuses me is (in MSVC) typeid(FunctionType) == typeid(FunctionTypeR) == "void __cdecl()", while typeid(FunctionTypeP) == "void (__cdecl*)()". If your theory is correct, I'd expect typeid(FunctionType) == "void (__cdecl*)()"? – Candy Chiu Sep 06 '11 at 16:02
  • @Candy: No, I did NOT say that `FunctionType` and `FunctionType*` are same. They're of different type. But in function parameter list, they're *equivalent*. – Nawaz Sep 06 '11 at 16:06
  • @Candy: I quoted the relevant text from the C++ Standard which talks about that they're equivalent when they appear in function parameter list. – Nawaz Sep 06 '11 at 16:11
  • 2
    There are a couple of subtle errors in this answer. For example, `FunctionType f` is correct, and it declares a function with the appropriate signature, what is not correct is trying to initialize it from a different function, so the problem is with the `= f` part, just as you cannot do: `void function() = f;`, which makes the *interesting part* less surprising or interesting. There is no such thing as *the equivalence property* (as a noun), what you are talking about is commonly known as *decay* (a function identifier decays into a pointer, as an array also decays to a pointer) – David Rodríguez - dribeas Sep 06 '11 at 16:56
  • @Nawaz: Why do we need FunctionType at all when the other 2 seems to supersede it in every way? – Zach Saw Jul 18 '12 at 07:21
  • 1
    @ZachSaw: You want to have pointer to function type, without having first the function type itself? Does it even make sense? :| – Nawaz Jul 18 '12 at 07:32