用户定义的文字s
不会在seconds
and之间“冲突” string
,即使它们都在范围内,因为它们像任何其他函数对一样在其不同的参数列表上重载:
string operator "" s(const char* str, size_t len);
seconds operator "" s(unsigned long long sec);
运行此测试可以证明这一点:
void test1()
{
using namespace std;
auto str = "text"s;
auto sec = 1s;
}
使用using namespace std
,两个后缀都在范围内,但不会相互冲突。
那为什么要inline namespace
跳舞呢?
基本原理是允许程序员根据需要公开尽可能少的标准定义名称。在上面的测试中,我已经将整个 std 库“导入”到了test
,或者至少与 #included 一样多。
test1()
不会工作namespace literals
没有inline
。
这是使用文字的更受限制的方式,无需导入整个 std:
void test2()
{
using namespace std::literals;
auto str = "text"s;
auto sec = 1s;
string str2; // error, string not declared.
}
这带来了所有标准定义的文字,但不是(例如)std::string
。
test2()
如果namespace string_literals
was notinline
和namespace chrono_literals
is not将无法工作inline
。
您还可以选择只公开字符串文字,而不是 chrono 文字:
void test3()
{
using namespace std::string_literals;
auto str = "text"s;
auto sec = 1s; // error
}
或者只是计时文字而不是字符串文字:
void test4()
{
using namespace std::chrono_literals;
auto str = "text"s; // error
auto sec = 1s;
}
最后,有一种方法可以公开所有的 chrono 名称和chrono_literals:
void test5()
{
using namespace std::chrono;
auto str = "text"s; // error
auto sec = 1s;
}
test5()
需要一点魔法:
namespace chrono { // hoist the literals into namespace std::chrono
using namespace literals::chrono_literals;
}
总而言之,inline namespace
s 是使所有这些选项对开发人员可用的工具。
更新
OP 在下面提出了一些很好的后续问题。他们(希望)在此更新中得到解决。
是using namespace std
不是个好主意?
这取决于。Ausing namespace
在作为通用库一部分的标头中的全局范围内从来都不是一个好主意。您不想将一堆标识符强制放入用户的全局命名空间中。该名称空间属于您的用户。
using namespace
如果标头仅针对您正在编写的应用程序存在,并且您认为所有这些标识符可用于包含该标头的所有内容,则全局范围可以在标头中使用。但是,您转储到全局范围内的标识符越多,它们就越有可能与某些东西发生冲突。 using namespace std;
引入了一堆标识符,并且随着标准的每个新版本都会引入更多标识符。因此,即使对于您自己的应用程序,我也不建议using namespace std;
在标头中使用全局范围。
但是,我可以在标头中看到using namespace std::literals
或using namespace std::chrono_literals
在全局范围内,但仅适用于应用程序标头,而不是库标头。
我喜欢using
在函数范围内使用指令,因为标识符的导入仅限于函数的范围。有了这样的限制,如果确实发生了冲突,解决起来就会容易得多。而且一开始就不太可能发生。
标准定义的文字可能永远不会相互冲突(今天不会)。但你永远不知道...
标准定义的文字永远不会与用户定义的文字冲突,因为标准定义的文字永远不会以 开头_
,而用户定义的文字必须以_
.
此外,对于库开发人员来说,在大型库的多个内联命名空间中是否有必要(或良好做法)没有冲突的重载?
这是一个非常好的问题,我认为陪审团仍然在这个问题上。但是,我恰好正在开发一个库,该库故意在不同的内联命名空间中具有冲突的用户定义文字!
https://github.com/HowardHinnant/date
#include "date.h"
#include "julian.h"
#include <iostream>
int
main()
{
using namespace date::literals;
using namespace julian::literals;
auto ymd = 2017_y/jan/10;
auto jymd = julian::year_month_day{ymd};
std::cout << ymd << '\n';
std::cout << jymd << '\n';
}
上面的代码无法编译并出现此错误消息:
test.cpp:10:20: error: call to 'operator""_y' is ambiguous
auto ymd = 2017_y/jan/10;
^
../date/date.h:1637:1: note: candidate function
operator "" _y(unsigned long long y) NOEXCEPT
^
../date/julian.h:1344:1: note: candidate function
operator "" _y(unsigned long long y) NOEXCEPT
^
_y
文字用于在此库中创建year
。这个库有一个公历(在“date.h”中)和一个儒略历(在“julian.h”中)。这些日历中的每一个都有一个year
类:(date::year
和julian::year
)。它们是不同的类型,因为公历年与儒略年不同。但是,将它们都命名year
并给它们_y
两个字面量仍然很方便。
如果我using namespace julian::literals;
从上面的代码中删除,那么它会编译并输出:
2017-01-10
2016-12-28
这表明 2016-12-28 Julian 与 2017-01-10 Gregorian 是同一天。这也是一个图形演示,同一天在不同的日历中可以有不同的年份。
只有时间会证明我使用冲突_y
的 s 是否会有问题。迄今为止还没有。然而,没有多少人使用这个图书馆与非公历。