22.2 Pointers and References to Functions

Ru-Brd

Consider the following fairly trivial definition of a function foo() :

 extern "C++" void foo() throw()  {  } 

The type of this function ought to be "function with C++ linkage that takes no arguments, returns no value, and does not throw any exceptions." For historical reasons, the formal definition of the C++ language does not actually make the exception specification part of a function type. [3] However, that may change in the future. It is a good idea to make sure that when you create code in which function types must match, the exception specifications also match. Name linkage (usually for "C" and "C++" ) is properly a part of the type system, but some C++ implementations are a little lax in enforcing it. Specifically, they allow a pointer to a function with C linkage to be assigned to a pointer to a function with C++ linkage and vice versa. This is a consequence of the fact that, on most platforms, calling conventions for C and C++ functions are identical as far as the common subset of parameter and return types is concerned .

[3] The historical origin of this is not clear, and the C++ standard is somewhat inconsistent in this area.

In most contexts, the expression foo undergoes an implicit conversion to a pointer to the function foo() . Note that foo itself does not denote the pointer, just as the expression ia after the declaration

 int ia[10]; 

does not denote a pointer to the array (or to the first element of the array). The implicit conversion from a function (or array) to a pointer is often called decay . To illustrate this, we can write the following complete C++ program:

  // functors/funcptr.cpp  #include <iostream>  #include <typeinfo>  void foo()  {      std::cout << "foo() called" << std::endl;  }  typedef void FooT();  //  FooT  is a function type,   // the same type as that of function  foo()  int main()  {      foo();  // direct call   // print types of  foo  and  FooT      std::cout << "Types of foo:  " << typeid(foo).name()                << '\n';      std::cout << "Types of FooT: " << typeid(FooT).name()                << '\n';      FooT* pf = foo;  // implicit conversion (decay)  pf();  // indirect call through pointer  (*pf)();  // equivalent to  pf()  // print type of  pf      std::cout << "Types of pf:   " << typeid(pf).name()                << '\n';      FooT& rf = foo;  // no implicit conversion  rf();  // indirect call through reference   // print type of  rf      std::cout << "Types of rf:   " << typeid(rf).name()                << '\n';  } 

This example shows various uses of function types, including some unusual ones.

The example uses the typeid operator, which returns a static type std::type_info , for which name() shows the types of some expressions (see Section 5.6 on page 58). No type decay occurs when typeid is applied to a function type.

Here is the output produced by one of our C++ implementations:

 foo() called  Types of foo:  void ()  Types of FooT: void ()  foo() called  foo() called  Types of pf:   FooT *  foo() called  Types of rf:   void () 

As you can see, this implementation keeps typedef names in the string returned by name() (for example, FooT * instead of its expanded form void (*)() ), but this is certainly not a language requirement.

This example also shows that references to functions exist as a language concept, but pointers to functions are almost always used instead (and to avoid confusion, it is probably best to keep with this use). Observe that the expression foo is in fact a so-called lvalue because it can be bound to a reference to a non- const type. However, it is not possible to modify that lvalue.

Note that the name of a pointer to a function (like pf ) or the name of a reference to a function (like rf ) can be used in a function call exactly like the name of a function itself. Hence, a pointer to a function is a functor ”an object that can be used in place of a function name in function call syntax. On the other hand, because a reference is not an object, a reference to a function is not a functor. Recall from our discussion of direct and indirect calls that behind these identical notations can be considerably different performance characteristics.

Ru-Brd


C++ Templates
C++ Templates: The Complete Guide
ISBN: 0201734842
EAN: 2147483647
Year: 2002
Pages: 185

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net