用户定义的文字s 不会在seconds 和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 一样多。
如果namespace literals 不是inline,test1() 将无法工作。
这是使用文字的更受限制的方式,无需导入整个 std:
void test2()
{
using namespace std::literals;
auto str = "text"s;
auto sec = 1s;
string str2; // error, string not declared.
}
这会引入所有标准定义的文字,但不会(例如)std::string。
如果namespace string_literals 不是inline 并且namespace chrono_literals 不是inline,test2() 将不起作用。
您也可以选择只公开字符串文字,而不是计时文字:
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;
}
最后有一种方法可以公开所有计时名称和计时文字:
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 namespaces 是一种工具,可让开发人员使用所有这些选项。
更新
OP 在下面提出了一些很好的后续问题。他们(希望)在本次更新中得到解决。
using namespace std 不是个好主意吗?
这取决于。 using namespace 在作为通用库一部分的标头中的全局范围内绝不是一个好主意。您不想将一堆标识符强制放入用户的全局命名空间中。该命名空间属于您的用户。
一个全局范围using namespace 可以在一个标头中使用,前提是该标头仅存在于您正在编写的应用程序中,并且如果您认为所有这些标识符都可用于包含该标头的所有内容,则您可以接受。但是,您转储到全局范围内的标识符越多,它们就越有可能与某些东西发生冲突。 using namespace std; 引入了 一堆 标识符,并且随着标准的每个新版本都将引入更多标识符。所以我不推荐 using namespace std; 在标头中的全局范围内,即使对于您自己的应用程序也是如此。
但是,我可以在标头的全局范围内看到 using namespace std::literals 或 using namespace std::chrono_literals,但仅限于应用程序标头,而不是库标头。
我喜欢在函数范围内使用using 指令,因为标识符的导入仅限于函数范围。有了这样的限制,如果确实发生了冲突,解决起来就会容易得多。而且从一开始就不太可能发生。
std 定义的文字将可能不会相互冲突(他们今天不会)。但你永远不知道...
std 定义的文字将永远与用户定义的文字发生冲突,因为 std 定义的文字永远不会以 _ 开头,而用户定义的文字 必须 开始_。
此外,对于库开发人员来说,是否有必要(或良好做法)在大型库的多个内联命名空间内没有冲突的重载?
这是一个非常好的问题,我认为陪审团仍然在这个问题上。但是,我恰好正在开发一个库,该库有目的地在不同的内联命名空间中有冲突的用户定义文字!
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 是同一天。这也是一个图形演示,同一天在不同的日历中可以有不同的年份。
只有时间会证明我使用冲突的_ys 是否会出现问题。迄今为止还没有。然而,没有多少人使用过这个库和非公历。