C++ std::literals的好处是什么:。。是内联名称空间吗?

C++ std::literals的好处是什么:。。是内联名称空间吗?,c++,namespaces,c++14,literals,inline-namespaces,C++,Namespaces,C++14,Literals,Inline Namespaces,在C++标准(如N4594)中,运算符有两种定义: 一个用于标准:计时:秒 namespace std { ... inline namespace literals { inline namespace chrono_literals { // 20.15.5.8, suffixes for duration literals constexpr chrono::seconds operator "" s(unsigned long long); 一个用于std::string: names

在C++标准(如N4594)中,
运算符有两种定义:

一个用于标准:计时:秒

namespace std {
...
inline namespace literals {
inline namespace chrono_literals {
// 20.15.5.8, suffixes for duration literals
constexpr chrono::seconds operator "" s(unsigned long long);
一个用于
std::string

namespace std { 
....
inline namespace literals {
inline namespace string_literals {
// 21.3.5, suffix for basic_string literals:
string operator "" s(const char* str, size_t len);
我想知道这些名称空间(以及
std::literals
中的所有其他名称空间)如果是
内联
,会有什么好处

我认为它们位于不同的名称空间中,所以它们不会相互冲突。但是当它们是内联的时,这种动机就没有了,对吗?编辑:因为主要动机是“库版本控制”,但这不适合这里

我可以看到“秒”和“字符串”的重载是不同的,因此不会冲突。但是如果重载相同,它们会冲突吗?或者采用(
inline
?)
名称空间
是否以某种方式防止了这种情况

因此,在
内联名称空间中使用它们有什么好处?

正如@Columbo在下面指出的,跨内联名称空间的重载是如何解决的,它们是否冲突?

用户定义的文本
s
字符串
之间不会“冲突”,即使它们都在作用域内,因为它们在不同的参数列表上像任何其他函数对一样重载:

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;
}
使用namespace std
时,两个后缀都在范围内,但不会相互冲突

那么为什么
内联名称空间
会跳舞呢

其基本原理是允许程序员根据需要公开尽可能少的std定义的名称。在上面的测试中,我已经将整个std库“导入”到
test
,或者至少导入了与包含的一样多的内容

test1()
如果没有
内联
名称空间文本
就不会工作

以下是一种更严格的使用文本的方法,无需导入整个std:

void test2()
{
    using namespace std::literals;
    auto str = "text"s;
    auto sec = 1s;
    string str2;  // error, string not declared.
}
这会引入所有std定义的文本,但不会(例如)
std::string

如果
名称空间字符串(文字)
不是
内联的
并且
名称空间时间(文字)
不是
内联的
,则
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 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_文字:

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;
}
总之,
inlinenamespace
s是开发人员可以使用的工具

更新

OP在下面提出了一些很好的后续问题。他们(希望)在本更新中得到解决

使用命名空间std
不是一个好主意吗

视情况而定。在作为通用库一部分的标头中,在全局范围内使用命名空间从来都不是一个好主意。您不希望将一堆标识符强制放入用户的全局命名空间中。该命名空间属于您的用户

如果报头只存在于您正在编写的应用程序中,并且您认为包含该报头的所有标识符都可用,那么在报头中使用名称空间的全局作用域
就可以了。但是,您在全局范围中转储的标识符越多,它们与某些内容冲突的可能性就越大<代码>使用名称空间std
引入了一系列标识符,并且随着标准的每一个新版本,将引入更多的标识符。所以我不建议
使用名称空间std在标题中的全局范围内,即使对于您自己的应用程序也是如此

但是,我可以看到
使用名称空间std::literals
使用名称空间std::chrono_literals
在报头的全局范围内,但仅适用于应用程序报头,而不是库报头

我喜欢在函数范围内使用
指令,因为标识符的导入仅限于函数范围。有了这样的限制,如果确实发生冲突,修复起来就容易多了。而且从一开始就不太可能发生

std定义的文字可能永远不会相互冲突(现在不会)。但你永远不知道

std定义的文字永远不会与用户定义的文字冲突,因为std定义的文字永远不会以
\uu
开头,而用户定义的文字必须以
\u
开头

此外,对于库开发人员来说,在大型库的几个内联名称空间中是否有必要(或良好实践)没有冲突的重载

这是一个非常好的问题,我认为这个问题还没有定论。然而,我恰好正在开发一个库,该库故意在不同的内联名称空间中具有冲突的用户定义文本

\u y
文字用于在此库中创建
年份
。这个图书馆有公历(date.h)和儒略历(Julian.h)。这些日历中的每一个都有一个
year
类:(
date::year
julian::year
)。它们是不同的类型,因为公历年和儒略年不是一回事。但是,将它们都命名为
year
还是很方便的,并且给它们都加上
\u y
文字

如果我使用名称空间julian::literals删除
从上面的代码中编译并输出:

2017-01-10
2016-12-28
这证明2016-12-28朱利安与2017-01-10格里高利是同一天。这也是一个图形演示,同一天在不同的日历中可以有不同的年份

只有时间才能证明我使用冲突的
\y
s是否有问题。到目前为止还没有。然而,很少有人将该库与非Gre一起使用