Resolved function pointer questions.


R. Clayton (rclayton@monmouth.edu)
(no date)


Some function pointer questions came up during lectures this week, and I could
only provide provisional answers. I can now provide somewhat more definitive
answers.

(These answers are only somewhat more definitive because I wasn't able to
figure out the exact answer in The Thousand Pages of Bjarne (The C++
Programming Language, third edition, Addison Wesley, 1997). Although I refer
to specific sections in the answers below, I can't be sure that there isn't
some little gotcha hidden away in some other part of the book that specifically
invalidates the answers given.)

That the two compilers agree means nothing. C++ is such a relentlessly complex
language that it's common for many compilers to make the same mistake
(c.f. Koenig lookup), particularly when the feature in question is somewhat
obscure.)

 1 Function pointers to external functions. A question came up about how a
   function pointer in one file can be set to the address of a function defined
   in another file. My answer suggested using an extern declaration in the
   function-pointer variable file, which appears to work:

     $ cat hw.cc
     #include <ostream>

     std::ostream & hw(std::ostream & os) {
       return os << "hello world!";
       }

     $ cat mn.cc
     #include <iostream>

     int main() {
       extern std::ostream & hw(std::ostream &);
       std::ostream & (* fp)(std::ostream &) = hw;
       fp(std::cout) << "\n";
       }

     $ g++ -o mn -ansi -pedantic -Wall hw.cc mn.cc

     $ ./mn
     hello world!

     $ CC -o mn mn.cc hw.cc
     mn.cc:
     hw.cc:

     $ ./mn
     hello world!

     $

   Section 9.2 in The Thousand Pages of Bjarne also suggests that this is the
   correct answer.

 2 Pointers to overloaded functions. A question also came up about pointers to
   overloaded functions. I gave two answers; the less probable answer was that
   it's illegal because you can't resolve which function should supply the
   address. The more probable answer was you use the type of the function
   pointer to determine which overloaded function should be used.

   The Thousand Pages of Bjarne, and in particular page 159, makes it clear
   that the more probable answer is the correct one.

     $ cat fp.cc
     #include <iostream>

     static char * f(int) {
       return "an int";
       }

     static char * f(double) {
       return "a double";
       }

     int main() {
       char * (* dfp)(double) = f;
       char * (* ifp)(int) = f;
       std::cout << "Whoa, it's " << dfp(1.0) << " argument.\n";
       std::cout << "Whoa, it's " << ifp(1) << " argument.\n";
       }

     $ g++ -o fp -ansi -pedantic -Wall fp.cc

     $ ./fp
     Whoa, it's a double argument.
     Whoa, it's an int argument.

     $ CC -o fp fp.cc

     $ ./fp
     Whoa, it's a double argument.
     Whoa, it's an int argument.

     $

  Make sure you understand what's being used here. This is
  function-pointer-type matching, not overload resolution. The main difference
  between the two is the function return value: it's used in
  pointer-pointer-type matching but not in overload resolution.

  The following code uses function-pointer type matching and is incorrect
  because the return types don't match:

     $ cat fp.cc
     #include <iostream>

     static double f(int i) {
       return i + 1.0;
       }

     int main() {
       int (* ifp)(int) = f;
       }

     $ g++ -o fp -ansi -pedantic -Wall fp.cc
     fp.cc: In function `int main()':
     fp.cc:8: warning: bad conversion from `double (*)(int)' to `int (*)(int)'
     fp.cc:8: warning: unused variable `int (*ifp)(int)'

     $ CC -o fp fp.cc
     "fp.cc", 8: Error: Cannot use double(*)(int) to initialize int(*)(int).
     1 Error(s) detected.

     $

  The following code uses overload resolution and is correct, because overload
  resolution doesn't involve return types:

     $ cat fp.cc
     #include <iostream>

     static double f(int i) {
       std::cout << "It's f(int)\n";
       return static_cast<double>(i) + 1.0;
       }

     static int f(double i) {
       std::cout << "It's f(double)\n";
       return static_cast<double>(i) + 1;
       }

     int main() {
       int i = f(1);
       }

     $ g++ -o fp -ansi -pedantic -Wall fp.cc
     fp.cc: In function `int main()':
     fp.cc:14: warning: initialization to `int' from `double'
     fp.cc:14: warning: argument to `int' from `double'
     fp.cc:14: warning: unused variable `int i'
     fp.cc:8: warning: `int f(double)' defined but not used

     $ ./fp
     It's f(int)

     $ CC -o fp fp.cc

     $ ./fp
     It's f(int)

     $



This archive was generated by hypermail 2.0b3 on Thu Dec 18 2003 - 16:15:05 EST