views:

894

answers:

4

Hello!

I am still learning C++ and I have never really created my own namespaces before. I was experimenting with them and while I got most things to work, there's one thing that I still can't seem to do. I would like to be able to call a static method within a class without typing something like "NameOfClass::method." Here is what I thought the code should look like, but it fails to compile:

A.h

namespace Test
{
    class A
    {
     public:
      static int foo() { return 42; }
    };
}

main.cpp

#include <iostream>

#include "A.h"

using namespace std;
using namespace Test::A;

int main()
{
    cout << foo() << endl;

    return 0;
}

The compiler gives me:

main.cpp:6: error: ‘A’ is not a namespace-name
main.cpp:6: error: expected namespace-name before ‘;’ token
main.cpp: In function ‘int main()’:
main.cpp:10: error: ‘foo’ was not declared in this scope

Is it possible to do what I am trying to do without typing "A::foo?" Thanks!

+5  A: 

There is no way around it you need to specify the class name for static methods.

using namespace Test;

Then:

int answerToEverything = A::foo();
Brian R. Bondy
That's a bummer. :-/
A: 

No, it's not possible to do what you're trying to do in any elegant fashion. The closest thing you'll be able to do are to create a macro or an inline function which delegates to your function. However, both of these alternatives are rather ugly, so I'm not going to post any code samples. Just bite the bullet and specify the whole name, or refactor your code so that the static methods are just global functions.

Adam Rosenfield
+9  A: 

In C++, you /especially/ have to read the compiler error messages carefully.

Notice the first error was "error: ‘A’ is not a namespace-name". That's true, A is a classname.

using namespace Foo; // brings in  all of foo;
using Bar::Baz // brings in only Baz from Bar

You want to write:

using Test::A;

That does two good things: it brings in A for you to use, and it doesn't bring in all the rest of Test, which is good too, because you should only bring in what you need, so as to not accidentally depend on something you don't realize you're depending upon.

However, as foo is static in A, you'll still have to refer to A::foo explicitly. (Unless you do something like writing a free function that forwards to A::foo; in general, this is a bad idea if you're only doing it to save some typing.)

Some may advise not using using declarations at all, instead fully qualifying all names.

But this is (to quote Stroustrup) "tedious and error prone", and it gets in the way of refactoring: say that you fully qualify every use of class FooMatic::Stack, and then management insists, just before you're about to go to production, that you use BarMatic's very similar Stack class, because barMatic just bought out your company.

Had you fully qualified everywhere, you'd be doing a lot of grepping, hoping your regex was right. If you used a using declaration, you can just make a fix to your (hopefully shared) header file. In this way, a using declaration is a lot like a "typedef int ourInt;" or a manifest constant or const: "const int FOO = 1;", in that it provides one place to change something that's referred to many places. Fully qualifying a namespace at every use takes away that benefit.

Conversely, had you used a using directive and brought in all of Namespace FooMatic, your grep might have been even harder, if say management insisted on BarMatic::Foo but you still had to use FooMatic:Baz, the BarMatic equivalent for Baz being for whatever reason unusable.

So bringing in one type (class, function, constant) at a time is generally the most flexible, the way to best protect yourself against inevitable but as yet unknown changes. As in most coding, you want to minimize tedious repetition while keeping sufficient granularity.

tpdi
I believe you mean, "you ALWAYS have to read the compiler error messages carefully".
Tom
There are plenty of tools out there that can do refactoring just fine; no regular expressions needed. I almost never use the 'using' declaration because it pollutes the global namespace, which is a worse problem to my mind. Refactoring is practically a non-issue.
Ben Collins
A: 

Don't be a "using namespace" abuser. Use those namespaces!

std::cout << Test::A::foo() << std::endl;
Terry Lorber