23

Most C++ programmers like me have made the following mistake at some point:

class C { /*...*/ };

int main() {
  C c();     // declares a function c taking no arguments returning a C,
             // not, as intended by most, an object c of type C initialized
             // using the default constructor.
  c.foo();   // compiler complains here.

  //...
}

Now while the error is pretty obvious once you know it I was wondering if there is any sensible use for this kind of local function declaration except that you can do it -- especially since there is no way to define such a local function in the same block; you have to define it elsewhere.

I think that Java-style local classes are a pretty nice feature which I tend to use often, especially the anonymous sort. Even local C++ classes (which can have inline-defined member functions) have some use. But this local function declaration without definition thing seems very awkward to me. Is it just a C-legacy or is there some deeper use case which I am not aware of?

Edit for the non-believers: C c() is not a function pointer declaration.

This program

int main()
{
  void g();
  cout << "Hello ";
  g();
  return 0;
}

void g()
{
  cout << "world." << endl;
}

outputs Hello world. This program

void fun()
{
  cout << "world." << endl;
}

int main()
{
  void g();
  g = fun;
  cout << "Hello ";
  g();
  return 0;
}

does not compile. gcc complains:

error: cannot convert 'void ()()' to 'void ()()' in assignment

comeau:

error: expression must be a modifiable lvalue
Thomas L Holaday
  • 13,614
  • 6
  • 40
  • 51
Tobias
  • 6,388
  • 4
  • 39
  • 64
  • Note that the GCC error message is wrong (known bug). It should output "error: cannot convert 'void ()' to 'void ()' in assignment" but it actually demangles the type-id incorrectly. (instead of "void()()", which would be a function returning a function (illegal type), it should say "void()") – Johannes Schaub - litb Jun 24 '09 at 08:04
  • related question: http://stackoverflow.com/questions/928992/nested-functions-are-not-allowed-but-why-nested-function-prototypes-are-allowed – Johannes Schaub - litb Jun 24 '09 at 08:22
  • I am not sure the gcc error message is a bug -- you can in fact declare the function with an extra pair of parenthesis `void (g)()`, which you need when dealing with function pointers: `void *g()` is a function returning a `void*`, while `void (*g)()` is a pointer to a function of type, well, `void ()()`, i.e. taking no arguments and not returning anything. – Tobias Jun 24 '09 at 09:34
  • @Tobias, that's exactly the problem. While void (a)(); is allowed, if you remove the identifier, then you have to remove redundant parentheses around it because it would be taken as a function declarator. If you consider the deriveration, it becomes clear: function: (), returning function: ()(), returning void: void ()() which is an invalid type. You may add parentheses for binding operators. Like you could say: function: (), returning function: (())(), returning void: void (())(). Or pointer: *, to function: (*)(), returning void: void (*)() (this happens to be valid, of course) – Johannes Schaub - litb Jun 24 '09 at 10:01
  • Feel free to tell them so they fix it: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36002 – Johannes Schaub - litb Jun 24 '09 at 10:06

7 Answers7

13

The only use I can think of is to reduce the scope of function declarations:

int main()
{
    void doSomething();
    doSomething();
    return 0;
}

void otherFunc()
{
    doSomething();  // ERROR, doSomething() not in scope
}

void doSomething()
{
    ...
}

Of course, there are much better solutions to this. If you need to hide a function, you should really restructure your code by moving functions into separate modules so that the functions which need to call the function you want to hide are all in the same module. Then, you can make that function module-local by declaring it static (the C way) or by putting it inside an anonymous namespace (the C++ way).

Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589
2

It's a forward declaration prototype. Conceivably if you have a lot of local functions, or local functions which call one another contrary to order of definition, you may need it.

chaos
  • 122,029
  • 33
  • 303
  • 309
  • I don't understand your point here: In your usecase, I would just declare all functions at the beginning of the source-file (or even in some private header) and then happily implement away. Why would I ever want/need to _declare_ one funciton inside another function? – Tobias Jun 23 '09 at 22:51
2

The only sane use for it I can see is to allow only one function in a compilation unit to know about a function defined in another compilation unit. I think that would be a somewhat reasonable use, but that's the only one I can think of, and I think that's overkill.

Rob K
  • 8,757
  • 2
  • 32
  • 36
  • But why would you declare a function inside the definition of another one (as opposed to outside the function definition or in a header)? – Tobias Jun 23 '09 at 22:45
  • 1
    Like I said, so that only that function could see it. – Rob K Jun 24 '09 at 17:32
2

I've wanted local function declarations in C when I wanted to pass them as arguments to some other function. I do this all the time in other languages. The reason is to encapsulate the implementation of data structures.

E.g. I define some data structure, e.g. a tree or a graph, and I don't want to expose the details of its internal implementation, e.g. because I may want to change or vary it. So I expose accessor and mutator functions for its elements, and a traversal function to iterate over the elements. The traversal function has as its argument a function that operates on an element; the traversal function's task is to execute the argument function on each element and possibly aggregate the results in some way. Now when I call the traversal function, the argument function is usually some specialized operation that depends on local state and therefore should be defined as a local function. Having to push the function, with the variables that contain the local state, outside to be global, or into an inner class created specifically to hold them, is butt ugly. But this is a problem I have with C and Java, not with C++.

reinierpost
  • 8,425
  • 1
  • 38
  • 70
  • OK, so you are saying it is a C legacy, which lost its purpose in C++? – Tobias Jun 24 '09 at 14:32
  • Not exactly. I am not actually experienced enough in C++ -- with or without templates -- to be able to tell how I would typically address this situation. Iterators are common in C++, but about traversal methods that take functions as arguments I'm not so sure. – reinierpost Jun 29 '09 at 22:50
  • Update: see http://stackoverflow.com/questions/2116128/easier-way-to-do-callbacks-for-vectors-or-maybe-something-else-in-the-stl-c – reinierpost Jan 22 '10 at 09:44
  • 2
    Sample code would be nice :) Eg, here is what I'd have to do if local function declarations were illegal, here it is using the local declaration. – Jon Oct 08 '10 at 02:42
2

Like said in the 3rd snippet of this answer, it can help with scope shadowing.

#include <stdio.h>

void c(); // Prototype of a function named ``c''

int main() {

    c(); // call the function

    { // additional scoppe needed for C, not for C++
        int c = 0; // shadow the c function with a c integer variable
        c++;
        {
            void c(); // hide the c integer variable back with the c function
            c();
        }
        ++c;
    } //!

    return 0;
}

void c() {
    printf("Called\n");
}

I don't think this use is likely to be useful often and there are chances that it won't arise in any well designed program.

I still think this is the most likely reason for that feature, defining functions lately as for variables just doesn't sound as right.

Community
  • 1
  • 1
ofavre
  • 4,488
  • 2
  • 26
  • 23
1

I sometimes do it for the same reason we are encouraged to declare variables right before their first use (and not earlier), namely, to improve readability. (Yes, I realize that for variables it is more important because it relieves you of the need to check whether the variable is used before what you think is its first use). Having the prototype (especially if it's more involved than just c()) close to the function invocation improves readability. The fact that the special case C c() is misleading to humans is unfortunate, but the general idea of declaring functions locally has merit.

Of course, this is true also for function names that are already in scope. Why not redeclare every function before its every use? My answer to that: do all things in moderation. Too much clutter impedes readability (as well as maintainability --- should the function's signature ever change). So while I wouldn't make a rule out of it, it is sometimes useful to declare functions locally.

Ari
  • 3,460
  • 3
  • 24
  • 31
  • Have you ever done it? Do you know someone who has ever done this? I don't, and it would be great if you could link to some _real_world example. This would be really interesting. – Tobias Jun 24 '09 at 09:37
  • I have a vague recollection of actually doing it once or twice, but I don't remember a specific instance. The thing is that most functions I call are class methods, so it is pretty rare. – Ari Jun 30 '09 at 10:32
-1

If you want to differ between declaring a function taking no parameters and instantiating a class with default destructor, skip the parenthesis.

class C
{
  public:
    void foo() {}
};


int main()
{
    // declare function d, taking no arguments, returning fresh C
    C d();

    // instantiate class (leave parenthesis out)
    C c;
    c.foo();

    // call declared function
    C goo = d();

    return 0;
}

C d()
{
    C c;
    // ..
    return c;
}
rtn
  • 127,556
  • 20
  • 111
  • 121
  • 1
    My question is not how to instantiate an object, my question is, why would you ever declare the function d the way you did it (as opposed to declaring it outside of main)? – Tobias Jun 23 '09 at 22:48