views:

465

answers:

6

I was reading the linked question which leads me to ask this question.

Consider the following code

int main()
{
    string SomeString();
}

All says, compiler takes this as a function prototype and not as a string object. Now consider the following code.

int main()
{
    string Some()
    {
        return "";
    }
}

Compiler said this is invalid as I guess nested function definition is not allowed. If it is not allowed, why nested function prototypes are allowed? It is not giving any advantage rather than making confusion (or am I missing some valid points here?).

I figured out the following is valid.

int main()
{ 
  string SomeFun();
  SomeFun();
  return 0;
}

string SomeFun()
{
  std::cout << "WOW this is unexpected" << std::endl;
}

This is also confusing. I was expecting the function SomeFun() will have a scope only in main. But I was wrong. Why compiler is allowing to compile code like the above? Is there any real time situations where code like the above makes sense?

Any thoughts?

+5  A: 

This is a convention from C -- like many -- which C++ has adopted.

The ability to declare a function inside another function in C is a decision that most programmers probably consider regrettable and unnecessary. Particularly with modern OOP design where function definitions are comparatively smaller than they are in C.

If you would like to have functions that only exist in the scope of another function, two options are boost::lambda and C++1x lambda.

Shmoopty
+7  A: 

Your prototype is just 'Forward Declaration'. Please check out the Wikipedia article.

Baseically, it tells the compiler "don't be alarmed if the label 'SomeFun' is used in this way". But your linker is what's responsible for finding the correct function body.

You can actually declare a bogus prototype, e.g. 'char SomeFun()' and use it all over your main. You will only get an error when your linker tries to find the body of your bogus function. But your compiler will be cool with it.

There are lots of benefits. You have to remember the function body is not always in the same source code file. It can be in a linked library. Also that linked library maybe have a specific 'link signature'. Use conditional defines you may even select the correct link signature at build time using your scoped prototypes. Although most people would use function pointers for that instead.

Hope this helps.

kervin
+3  A: 

Function prototypes are hints for the compiler. They indicate that the functions are implemented somewhere else, if not already discovered. Nothing more.

Nick D
+3  A: 

When you declare a prototype as you are doing you are basically telling the compiler to wait for the linker to resolve it. Depending where you write the prototype the scoping rules apply. There is nothing technically wrong writing the prototype inside your main() function (although IMHO a bit messier), it just means that the function is only locally known inside the main(). If you would have declared the prototype at the top of your source file (or more commonly in a header file), the prototype/function would be known in the whole source.

string foo()
{
  string ret = someString();  // Error
  return ret; 
}

int main(int argc,char**argv)
{
   string someString();
   string s = somestring(); // OK
   ...
}
Anders K.
+5  A: 

Just as a side note, C++03 does have a roundabout way of defining local functions. It requires abusing the local-class feature:

int main()
{
    struct Local
    {
        static string Some()
        {
            return "";
        }
    };
    std::cout << Local::Some() << std::endl;
}
Awesome abuse of the language.
Joshua
+4  A: 

As to why your declaration of

void f() {
    void g(); g();
}

is better than this one

void g();
void f() {
    g();
}

It's generally good if you keep declarations as local as possible, so that as few name clashes as possible result. I say it's arguable whether declaring a function locally (this way) is really fortunate, as i think it's still better to ordinary include its header and then go the "usual" way, which is also less confusing to people not knowing about that. Sometimes, it's also useful to work around a shadowed function

void f() {
    int g; 
    // oops, ::g is shadowed. But we can work around that
    {
        void g(); g();
    }
}

Of course, in C++ we could call function g using its_namespace::g() - but in the old days of C, that wouldn't have been possible, and that thing allowed the programmer to still access the function. Also note that while syntactically it is not the same, semantically the following does also declare a function within a local scope, that actually targets a different scope.

int main() {
    using std::exit;
    exit();
}

As a side note, there are more situations like that where the target scope of a declaration is not the scope where that declaration appears in. In general, the entity you declare becomes a member of the scope in which the declaration appears. But that's not always the case. Consider for example friend declarations, where that thing happens

struct X { friend void f() { std::cout << "WoW"; } };
int main() { void f(); f(); } // works!

Even though the function declaration (and definition!) of f happened within the scope of X, the entity (the function itself) became a member of the enclosing namespace.

Johannes Schaub - litb
Nice explanation. Many thanks litb
Appu