C++ 使用命名空间来避免长路径
我仍在学习 C++,之前从未真正创建过自己的命名空间。 我正在用它们进行实验,虽然我完成了大部分工作,但有一件事我似乎仍然无法做到。 我希望能够在类中调用静态方法,而无需输入类似 NameOfClass::method
的内容。 这是我认为代码应该是这样的,但它无法编译:
文件 Ah
,
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
的情况下进行操作?
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:
File A.h
,
namespace Test
{
class A
{
public:
static int foo() { return 42; }
};
}
File 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
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
在 C++ 中,您/尤其是/必须仔细阅读编译器错误消息。
请注意,第一个错误是“错误:‘A’不是命名空间名称”。 确实如此,A 是一个类名。
你想写:
这有两个好处:它引入 A 供你使用,并且它不会引入 Test 的所有其余部分,这也很好,因为你应该只引入你需要的内容,以便不要意外地依赖于你没有意识到自己正在依赖的东西。
但是,由于 foo 在 A 中是静态的,因此您仍然必须显式引用 A::foo 。 (除非你做了一些事情,比如编写一个转发到 A::foo 的自由函数;一般来说,如果你这样做只是为了节省一些打字,那么这是一个坏主意。)
有些人可能建议根本不使用 using 声明,而是完全限定所有名称。
但这是(引用 Stroustrup 的话)“乏味且容易出错”,并且它妨碍了重构:假设您完全限定了 FooMatic::Stack 类的每次使用,然后管理层坚持要求,就在您准备这样做之前进入生产,你使用 BarMatic 非常相似的 Stack 类,因为 barMatic 刚刚买下了你的公司。
如果您在所有地方都完全合格,您将进行大量的 grep 操作,希望您的正则表达式是正确的。 如果您使用了 using 声明,则只需修复您的(希望是共享的)头文件即可。 这样,using 声明很像“typedef int ourInt;” 或一个明显的常量或 const:“const int FOO = 1;”,因为它提供了一个位置来更改引用到多个位置的内容。 在每次使用时完全限定命名空间会消除这一好处。
相反,如果您使用 using 指令并引入所有名称空间 FooMatic,那么您的 grep 可能会更加困难,如果说管理层坚持使用 BarMatic::Foo 但您仍然必须使用 FooMatic:Baz,BarMatic 相当于 Baz 的无论什么原因都无法使用。
因此,一次引入一种类型(类、函数、常量)通常是最灵活的,也是最好的保护自己免受不可避免但未知的变化影响的方法。 与大多数编码一样,您希望最大限度地减少繁琐的重复,同时保持足够的粒度。
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.
You want to write:
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.
没有办法解决这个问题,您需要为静态方法指定类名。
然后:
There is no way around it you need to specify the class name for static methods.
Then:
不,不可能以任何优雅的方式做你想做的事情。 您能够做的最接近的事情是创建一个委托给您的函数的宏或内联函数。 然而,这两种选择都相当难看,所以我不会发布任何代码示例。 只需硬着头皮指定整个名称,或者重构代码,使静态方法只是全局函数。
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.
不要成为“使用命名空间”的滥用者。 使用这些命名空间!
Don't be a "using namespace" abuser. Use those namespaces!