我还在学习C ++,之前我从未真正创建过自己的命名空间。我正在试验它们,当我得到大部分工作时,有一件事我似乎无法做到。我希望能够在类中调用静态方法而无需键入NameOfClass::method
之类的内容。这是我认为代码应该是什么样子,但它无法编译:
档案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;
}
编译器给了我:
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
是否可以在不输入A::foo
的情况下执行我要执行的操作?
答案 0 :(得分:10)
在C ++中,您/尤其/必须仔细阅读编译器错误消息。
注意第一个错误是“错误:'A'不是命名空间名称”。这是真的,A是一个类名。
using namespace Foo; // brings in all of foo;
using Bar::Baz // brings in only Baz from Bar
你想写:
using Test::A;
这有两个好处:它带来了A供你使用,并没有带来所有其余的测试,这也很好,因为你应该只带来你需要的东西,以免意外地依赖于你没有意识到你依赖的东西。
然而,由于foo在A中是静态的,你仍然必须明确地引用A :: foo。 (除非你做一些像编写一个转发到A :: foo的免费函数的东西;一般来说,如果你只是为了节省一些打字,这是一个坏主意。)
有些人可能会建议不要使用声明,而是完全限定所有名称。
但这是(引用Stroustrup)“乏味且容易出错”,并且它妨碍了重构:说你完全符合FooMatic :: Stack类的每一次使用,然后管理层坚持,就在你之前'重新投入生产,你使用BarMatic非常相似的Stack类,因为barMatic刚收购了你的公司。
如果你在任何地方完全合格,你会做很多的捣蛋,希望你的正则表达式是正确的。如果您使用了using声明,则可以修复您的(希望共享的)头文件。这样,using声明很像“typedef int ourInt”。或者一个清单常量或const:“const int FOO = 1;”,因为它提供了一个地方来改变被引用到许多地方的东西。在每次使用时完全限定名称空间都会带来好处。
相反,如果您使用了using指令并引入了所有的Namespace FooMatic,那么你的grep可能会更难,如果说管理层坚持使用BarMatic :: Foo但是你仍然必须使用FooMatic:Baz,BarMatic等效于Baz因任何原因无法使用。
因此,一次引入一种类型(类,函数,常量)通常是最灵活的,最好地保护自己免受不可避免的但尚未知的变化。与大多数编码一样,您希望在保持足够粒度的同时最大限度地减少繁琐的重复。
答案 1 :(得分:5)
无法解决此问题,您需要为静态方法指定类名。
using namespace Test;
然后:
int answerToEverything = A::foo();
答案 2 :(得分:0)
不,不可能以任何优雅的方式做你想做的事。您能够做的最接近的事情是创建一个委托给您的函数的宏或内联函数。但是,这两种选择都相当难看,所以我不打算发布任何代码示例。只需咬紧牙关并指定整个名称,或重构代码,以便静态方法只是全局函数。
答案 3 :(得分:0)
不要成为“使用命名空间”的滥用者。使用这些名称空间!
std::cout << Test::A::foo() << std::endl;