库和命名空间之间的关系是什么?
What's the relation between libraries and namespaces?
刚开始拼贴,我是编程界的新手。因此,当我学习 C++ 时,我遇到了一个问题,这个问题不会让我成为:“如果我已经有了 iostream,为什么我需要在我的代码中包含“using namespace std”以便能够写入或读取?” ,因为有人告诉我“cin/cout”已经在 iostream 库中定义,但我注意到如果我单独编写其中一行,它会出现编译错误。因此,iostream 和“std”命名空间之间的关系是什么......有人可以解释一下吗?谢谢! <3
#include 与使用
简单来说:
#include <iostream> // include the header
int main() {
// now you can use stuff declared in that header
std::cout << "Hello world" << std::endl;
// if you are lazy you can "use" things:
using std::cout;
using std::endl;
cout << "Hello World" << endl;
}
你不必写using namespace std;
!适合这样做的情况非常罕见,而真正造成巨大伤害的情况却如此频繁,因此您可以记住一条经验法则:永远不要使用它!有关详细信息,请参见此处:Why is “using namespace std;” considered bad practice?。重要的是要认识到完全限定名称 std::cout
和不完全限定名称 cout
之间的区别不仅仅是输入或多或少 5 个字符(继续阅读...) .
库与命名空间
What's the relation between libraries and namespaces?
标准库将所有内容都放在 std
命名空间中。命名空间有助于保持事物的分离。不同的库可以包含 other_namespace::vector
并且不会与 std::vector
混淆,因为我们有名称空间。
非常酷的东西
使用命名空间的一个更深层次的原因是 Argument Dependent Lookup。我将尝试用一个简单的例子来解释。假设您正在使用一个带有某些函数模板的库,该函数模板使用您必须提供的类型 objects 执行某些操作:
namespace library {
template<typename T>
void do_something(T& a,T& b){
std::cout << "wrong...\n";
std::swap(a,b); // (1)
std::cout << "correct\n";
using std::swap;
swap(a,b); // (2)
}
}
我拿了两个 objects 并交换了两次。你必须耐心等待我理解为什么 (1) 是错误的而只有 (2) 是正确的。现在我们有一个库函数模板,要使用它我们需要一些类型 T
:
namespace A {
struct foo{};
void swap(foo& a,foo& b) {
std::cout << "A::swap" << "\n";
}
}
想象一下foo
是这样的,我们知道比std::swap
到swap
更好的实例。其实foo
是空的,所以要swap
两个objects我们什么都不做。
让我们回顾一下:标准库附带了 std::swap
。有人写了一个我们要用的库(叫library
)。我们希望库代码调用 A::swap
而不是 std::swap
。库作者甚至不知道 A::swap
存在。
加上上面的A
和library
,这个代码
int main() {
A::foo a,b;
library::do_something(a,b);
}
将打印:
wrong...
correct
A::swap
Live Example。发生了什么?这一行:
std::swap(a,b); // (1)
调用 std::swap
,毫无疑问。不是我们想要的。我们希望库代码调用我们的 A::swap
.
现在这个:
using std::swap;
swap(a,b); // (2)
第一行将名称swap
从std
拉入函数范围。在第二行中,ADL 终于启动了,因为它说的是 swap
而不是 std::swap
。 ADL 简而言之是:a
和 b
来自命名空间 A
,因此当编译器搜索所有可能的 swap
时,它也会在 A
中搜索。如果它在 A
中找到一个,那么它会调用它(如果它在 A
中没有找到一个,那么 swap
仍然来自 std
)。因此只有 (2) 调用我们的自定义交换。
这仅适用于名称空间。 “很酷的东西”是库作者不需要知道任何关于您的命名空间的信息,但他们的库代码仍然会从您的命名空间调用您的函数(如果它存在)。
我应该注意,并非所有代码都是通用库代码。通常,您想编写代码,了解每个细节中发生的情况,您想知道调用了哪些函数。通常您不希望您的代码根据包含或不包含特定的 header 而表现不同。因此,许多代码最好使用完全合格的函数调用:std::foo
.
结论
我希望我能让你相信命名空间不仅仅是输入或多或少的一些字符。 using namespace std;
懒惰完全忽略了名称空间的要点。另一方面,通过 using std::foo; foo();
将名称拉入范围是
完全正常并启用 ADL。
iostream 是一个库。这是有人为您编写的代码,因此您不必这样做。通过添加 #include <iostream>
,您告诉预处理器粘贴该代码。但是此代码提供的函数和结构的名称可能会干扰其他名称。但这不是问题,因为您可以通过将它们放在 命名空间 中来将它们分开,STL(上游是其中的一部分)使用 std
(简称标准,发音为 'stood')。当某些东西在命名空间中时,您必须命名该命名空间才能访问其中的内容。即 std::cout
。但有时您不希望每次要从 STL 访问某些内容时都必须编写 std::
。这就是 using namespace std
为您所做的。这样,您只需键入 cout
。但这是一个very bad idea!
库和命名空间按照约定相关联。
按照惯例,库提供给 programmer-user 的符号包含在命名空间中。这样可以组织事物,并且有一些更高级别的语言功能 (ADL),这意味着命名空间中的代码与外部代码的行为不同。
当你键入 using namespace std;
时,你告诉编译器“当你 运行 进入一个符号时,还要查看 std
以确定你是否可以确定它是什么”。在“文件”范围内执行此操作通常是一个非常非常糟糕的主意;在一个简短的函数中完成它是可行的,但超过这个可能会导致非常棘手的错误。
与 namespace std
交互的标准、专业方式是在您的符号前加上命名空间:
std::cout << "Hello world\n";
而不是
using namespace std;
cout << "Hello world\n";
绝对不会:
using namespace std;
int main() {
cout << "Hello world\n";
}
您还可以获取单个符号,这没有导入整个命名空间那么糟糕:
using std::cout;
cout << "Hello world\n";
但也应避免出现在“文件”范围内。
#include <iostream>
这包括系统搜索路径中名为 iostream
的 头文件 。 iostream
是标准库的一部分。按照惯例(和 C++ 标准),iostream
为您的程序提供的符号位于 namespace std
.
中
通过将符号放在名称空间中,可以避免与您的代码 发生冲突。 std
中有很多很多符号,如果 #include <iostream>
将一些未知数量的符号推入您的全局命名空间,您很容易出错或以意想不到的方式调用错误的函数。
std::cout
和 using namespace std; cout
和 using std::cout
都是告诉编译器在什么命名空间中找到符号 cout
.
的方法
#include <iostream>
在 namespace std
中包含 cout
;没有它,您的代码就不知道它的存在。
C++从C发展而来,C有textual包含模型。 #include
实际上是把文件 iostream
和 copy/pastes 的内容放到你的文件中。然后您的编译器读取该扩展文件并在 <iostream>
.
中找到符号
因为这个文本包含可能会推 LOT 的东西,将它隔离到 namespace
可以防止你,程序员出现问题。
最近,C++ 添加了 模块 。模块是 #include
指令的替代方法,因为它直接从库中获取符号并将其注入您的代码 而无需大量复制粘贴 .
在模块中,命名空间仍然没有直接连接到模块。你可以
import std;
或
import std.iostream;
这只会将仍在 namespace std
中的 std
库符号导入您的代码。 (C++标准添加了模块,但还没有模块化std库,所以上面的名字都是猜测)
符号查找与符号导入没有直接关系。
这样可以大块地完成符号导入,同时更仔细地进行查找。
Libraries
图书馆有部分代码 pre-written 可以为您提供功能。可以是 functions/overloaded 运算符等形式
有两种类型的库:
标准库,例如#include <iostream>
并且库的名称在尖括号中。
用户 defined/made 例如#include "randomLib.h"
库名用双引号括起来。
Namespaces
当您的项目需要多个库时。两者都可能包含多个具有相同名称的方法(函数定义),或者单个库可能使用相同的函数名称但在不同的命名空间中。命名空间用于消除编译器和用户的混淆或歧义。
- 假设 lib 1 有
namespace abc{ foo(); }
而 lib 2 有 namespace def{ foo(); }
因此,您将为所需的功能执行 abc::foo()
或 def::foo()
。这里 abc/def 是 namespace
,::
称为作用域解析运算符,foo()
是您调用的方法。
刚开始拼贴,我是编程界的新手。因此,当我学习 C++ 时,我遇到了一个问题,这个问题不会让我成为:“如果我已经有了 iostream,为什么我需要在我的代码中包含“using namespace std”以便能够写入或读取?” ,因为有人告诉我“cin/cout”已经在 iostream 库中定义,但我注意到如果我单独编写其中一行,它会出现编译错误。因此,iostream 和“std”命名空间之间的关系是什么......有人可以解释一下吗?谢谢! <3
#include 与使用
简单来说:
#include <iostream> // include the header
int main() {
// now you can use stuff declared in that header
std::cout << "Hello world" << std::endl;
// if you are lazy you can "use" things:
using std::cout;
using std::endl;
cout << "Hello World" << endl;
}
你不必写using namespace std;
!适合这样做的情况非常罕见,而真正造成巨大伤害的情况却如此频繁,因此您可以记住一条经验法则:永远不要使用它!有关详细信息,请参见此处:Why is “using namespace std;” considered bad practice?。重要的是要认识到完全限定名称 std::cout
和不完全限定名称 cout
之间的区别不仅仅是输入或多或少 5 个字符(继续阅读...) .
库与命名空间
What's the relation between libraries and namespaces?
标准库将所有内容都放在 std
命名空间中。命名空间有助于保持事物的分离。不同的库可以包含 other_namespace::vector
并且不会与 std::vector
混淆,因为我们有名称空间。
非常酷的东西
使用命名空间的一个更深层次的原因是 Argument Dependent Lookup。我将尝试用一个简单的例子来解释。假设您正在使用一个带有某些函数模板的库,该函数模板使用您必须提供的类型 objects 执行某些操作:
namespace library {
template<typename T>
void do_something(T& a,T& b){
std::cout << "wrong...\n";
std::swap(a,b); // (1)
std::cout << "correct\n";
using std::swap;
swap(a,b); // (2)
}
}
我拿了两个 objects 并交换了两次。你必须耐心等待我理解为什么 (1) 是错误的而只有 (2) 是正确的。现在我们有一个库函数模板,要使用它我们需要一些类型 T
:
namespace A {
struct foo{};
void swap(foo& a,foo& b) {
std::cout << "A::swap" << "\n";
}
}
想象一下foo
是这样的,我们知道比std::swap
到swap
更好的实例。其实foo
是空的,所以要swap
两个objects我们什么都不做。
让我们回顾一下:标准库附带了 std::swap
。有人写了一个我们要用的库(叫library
)。我们希望库代码调用 A::swap
而不是 std::swap
。库作者甚至不知道 A::swap
存在。
加上上面的A
和library
,这个代码
int main() {
A::foo a,b;
library::do_something(a,b);
}
将打印:
wrong...
correct
A::swap
Live Example。发生了什么?这一行:
std::swap(a,b); // (1)
调用 std::swap
,毫无疑问。不是我们想要的。我们希望库代码调用我们的 A::swap
.
现在这个:
using std::swap;
swap(a,b); // (2)
第一行将名称swap
从std
拉入函数范围。在第二行中,ADL 终于启动了,因为它说的是 swap
而不是 std::swap
。 ADL 简而言之是:a
和 b
来自命名空间 A
,因此当编译器搜索所有可能的 swap
时,它也会在 A
中搜索。如果它在 A
中找到一个,那么它会调用它(如果它在 A
中没有找到一个,那么 swap
仍然来自 std
)。因此只有 (2) 调用我们的自定义交换。
这仅适用于名称空间。 “很酷的东西”是库作者不需要知道任何关于您的命名空间的信息,但他们的库代码仍然会从您的命名空间调用您的函数(如果它存在)。
我应该注意,并非所有代码都是通用库代码。通常,您想编写代码,了解每个细节中发生的情况,您想知道调用了哪些函数。通常您不希望您的代码根据包含或不包含特定的 header 而表现不同。因此,许多代码最好使用完全合格的函数调用:std::foo
.
结论
我希望我能让你相信命名空间不仅仅是输入或多或少的一些字符。 using namespace std;
懒惰完全忽略了名称空间的要点。另一方面,通过 using std::foo; foo();
将名称拉入范围是
完全正常并启用 ADL。
iostream 是一个库。这是有人为您编写的代码,因此您不必这样做。通过添加 #include <iostream>
,您告诉预处理器粘贴该代码。但是此代码提供的函数和结构的名称可能会干扰其他名称。但这不是问题,因为您可以通过将它们放在 命名空间 中来将它们分开,STL(上游是其中的一部分)使用 std
(简称标准,发音为 'stood')。当某些东西在命名空间中时,您必须命名该命名空间才能访问其中的内容。即 std::cout
。但有时您不希望每次要从 STL 访问某些内容时都必须编写 std::
。这就是 using namespace std
为您所做的。这样,您只需键入 cout
。但这是一个very bad idea!
库和命名空间按照约定相关联。
按照惯例,库提供给 programmer-user 的符号包含在命名空间中。这样可以组织事物,并且有一些更高级别的语言功能 (ADL),这意味着命名空间中的代码与外部代码的行为不同。
当你键入 using namespace std;
时,你告诉编译器“当你 运行 进入一个符号时,还要查看 std
以确定你是否可以确定它是什么”。在“文件”范围内执行此操作通常是一个非常非常糟糕的主意;在一个简短的函数中完成它是可行的,但超过这个可能会导致非常棘手的错误。
与 namespace std
交互的标准、专业方式是在您的符号前加上命名空间:
std::cout << "Hello world\n";
而不是
using namespace std;
cout << "Hello world\n";
绝对不会:
using namespace std;
int main() {
cout << "Hello world\n";
}
您还可以获取单个符号,这没有导入整个命名空间那么糟糕:
using std::cout;
cout << "Hello world\n";
但也应避免出现在“文件”范围内。
#include <iostream>
这包括系统搜索路径中名为 iostream
的 头文件 。 iostream
是标准库的一部分。按照惯例(和 C++ 标准),iostream
为您的程序提供的符号位于 namespace std
.
通过将符号放在名称空间中,可以避免与您的代码 发生冲突。 std
中有很多很多符号,如果 #include <iostream>
将一些未知数量的符号推入您的全局命名空间,您很容易出错或以意想不到的方式调用错误的函数。
std::cout
和 using namespace std; cout
和 using std::cout
都是告诉编译器在什么命名空间中找到符号 cout
.
#include <iostream>
在 namespace std
中包含 cout
;没有它,您的代码就不知道它的存在。
C++从C发展而来,C有textual包含模型。 #include
实际上是把文件 iostream
和 copy/pastes 的内容放到你的文件中。然后您的编译器读取该扩展文件并在 <iostream>
.
因为这个文本包含可能会推 LOT 的东西,将它隔离到 namespace
可以防止你,程序员出现问题。
最近,C++ 添加了 模块 。模块是 #include
指令的替代方法,因为它直接从库中获取符号并将其注入您的代码 而无需大量复制粘贴 .
在模块中,命名空间仍然没有直接连接到模块。你可以
import std;
或
import std.iostream;
这只会将仍在 namespace std
中的 std
库符号导入您的代码。 (C++标准添加了模块,但还没有模块化std库,所以上面的名字都是猜测)
符号查找与符号导入没有直接关系。
这样可以大块地完成符号导入,同时更仔细地进行查找。
Libraries
图书馆有部分代码 pre-written 可以为您提供功能。可以是 functions/overloaded 运算符等形式
有两种类型的库:
标准库,例如
#include <iostream>
并且库的名称在尖括号中。用户 defined/made 例如
#include "randomLib.h"
库名用双引号括起来。
Namespaces
当您的项目需要多个库时。两者都可能包含多个具有相同名称的方法(函数定义),或者单个库可能使用相同的函数名称但在不同的命名空间中。命名空间用于消除编译器和用户的混淆或歧义。
- 假设 lib 1 有
namespace abc{ foo(); }
而 lib 2 有namespace def{ foo(); }
因此,您将为所需的功能执行 abc::foo()
或 def::foo()
。这里 abc/def 是 namespace
,::
称为作用域解析运算符,foo()
是您调用的方法。