tags:

views:

401

answers:

5

I have couple questions regarding some C++ rules.

  1. Why am I able to call a function/method from outside the class in the namespace when I include the return type? (look at the namespace test2::testclass2 in the code below) i.e. this works:

    bool b = testclass1::foo<int>(2);
    

    whereas this doesn't: - (it doesn't even compile - compiler throws that this is function redeclaration)

    testclass1::foo<int>(2);
    

    C++ complains that it is a function redeclaration. Is that so?

  2. This line:

    bool b = testclass1::foo<int>(2);
    

    gets called first before anything else. Is this because static methods get created always first before anything else in C++?

  3. Where can I find those rules? I have a few C++ books at home, so if someone would be kind enough to either point out a book (and chapter or page) or direct me to a website I would greatly appreciate it.

Here below is the sample (partial) code that I tested at home with Visual Studio 2008:

class testclass1
    {
    public:
     testclass1(void);
     ~testclass1(void);

     template<class A> static bool foo(int i)
     {
      std::cout <<"in static foo"; 
      return true;
     }
    };


namespace test2
{
    class testclass2
    {
    public:
     testclass2(void);
     ~testclass2(void);
    };

    bool b = testclass1::foo<int>(2);
}

EDIT:

A few people mentioned that I need to call this inside the function and this will work without any problem.
I understand that; the only reason I asked this question is because I saw this code somewhere (in someone's elses project) and was wondering how and why this works. Since I never really seen anyone doing it before.

Also, this is used (in multiple places) as a way to call and instantiate a large number of classes like this via those function calls (that are outside). They get called first before anything else is instantiated.

+3  A: 

C++ is not Python. You write statements in functions and execution starts from the main method. The reason bool b = ... happens to work is that it's defining the global variable b and the function call is merely the initialization expression.

Definitions can exist outside functions while other statements can only exist inside a function body.

Mehrdad Afshari
so what's you're saying is that the only reason it works because it's treated as a global declaration and has nothing to do with static?so, are all global declaration executed before anything else?
Tom
Tom: Yes, `static` is not relevant here. Look at this answer: http://stackoverflow.com/questions/646169/changing-c-output-without-changing-the-main-function/646182#646182
Mehrdad Afshari
"are all global declaration executed before anything else" - depends on what you mean by "anything else". Global declarations are executed first, but their initializers can call functions, so it may happen that code inside some function runs before initializer for some global variable does (if it is called from initializer of another global variable).
Pavel Minaev
@Pavel: Indeed.
Mehrdad Afshari
Actually in C++ `bool b;` (even without initialization) is a _definition_, not a declaration. Definitions can exist at namespace scope, too.
sbi
sbi: I'm not intimately familiar with the terminology used in the C++ spec. You are probably correct about the name. Terminology aside, the point of this answer is you are *declaring* something and assigning a value to it. You can do it in a namespace but you can't put arbitrary statements there.
Mehrdad Afshari
@Mehrdad: And you are correct in that, except that you need to swap "declaring" with "defining", as `bool b = foo()` is a definition ob `b` - which is just as fine at namespace scope.
sbi
Perfect, now I up-voted this. `:)`
sbi
+3  A: 

Why am I able to call a function/method from outside the class in the namespace when I include the return type? (look at the namespace test2::testclass2)

Your declaration of b is not inside a function, so you are declaring a global variable. If you were inside a function's scope, your second statement would work, but outside a function it makes no sense.

This also answers your second question.

Of course, you wouldn't be allowed to call it this way (i.e. not as a method of an object) if it weren't a static member function.

rlbond
A: 

You can find the rules on e.g. Koenig lookup and template in the standard documentation -- good luck with navigating that! You're not mentioning which compiler you are testing, but I'm not entirely sure it's compliant!

As Mehrdad points out, you're declaring and initializing a global variable within the test2 namespace: this has nothing to do with static methods.

Pontus Gagge
I did mention that I tested this with visual studio 2008
Tom
Since he's using fully qualified name in a call, Koenig lookup really has nothing to do with this.
Pavel Minaev
A: 

if you write this inside a function like below then it works without a problem. As mentioned above, you need to call these functions from within a function unless you are using the function to initialize a global variable ...

int main()
{
    testclass1::foo<int>(2);
    return 0;
}
Stephen Doyle
A: 

1. First, a helpful correction: you said "...when I include the return type". I think you might be misunderstanding what the <int> part of testclass1::foo<int>(2) does. It doesn't (necessarily) specify the return type, it just provides a value for the template argument "A".

You could have chosen to use A as the return type, but you have the return type hard-coded to "bool".

Basically, for the function as you have written it you will always need to have the <> on it in order to call it. C++ does allow you to omit the <args> off the function when the type can be deduced from the function arguments; in order to get it to do that you have to use the type argument A in your function arguments. For instance if you declared the function this way instead then you could call it without the <>:

template<class A> static bool foo(A i);

In which case it you could call "foo(2)" and it would deduce A to be "int" from the number two.

On the other hand there isn't any way to make it deduce anything based on what you assign the function to. For template argument deduction it only looks at the arguments to the function, not what is done with the result of calling the function. So in:

bool b = testclass1::foo(2);

There is no way to get it to deduce "bool" from that, not even if you made A the return type.

So why doesn't the compiler just tell you "you needed to use <> on the function"? Even though you declared foo once as a template function, you could have also overloaded it with a non-template version too. So the compiler doesn't just automatically assume that you're trying to call a template function when you leave the <> off the call. Unfortunately having NOT assumed you were calling template-foo and not seeing any other declaration for foo, the compiler then falls back on an old C style rule where for a function that takes an int and returns an int, in a very old dialect of C you didn't need to declare that kind of before using it. So the compiler assumed THAT was what you wanted - but then it notices that template-foo and old-crufty-C-foo both take an int parameter, and realizes it wouldn't be able to tell the difference between them. So then it says you can't declare foo. This is why C++ compilers are notorious for giving bad error messages - by the time the error is reported the compiler may have gone completely off the rails and be talking about something that is three or four levels removed from your actual code!

2. Yes you're exactly right.

3. I find that the C++ references and whitepapers that IBM makes available online are the most informative. Here's a link to the section about templates: C++ Templates

Dennis