向 std 注入命名空间 experimental。

11

在编程中,将命名空间std::experimental注入到std中是否是一种好的或者不好的实践方式?

namespace std
{
namespace experimental
{
}
using namespace experimental;    
}

#include <experimental/optional>

int main()
{
    std::optional< int > o;
    return 0;
}

或者更现代化的形式:

#if __has_include(<optional>)
# include <optional>
#elif __has_include(<experimental/optional>)
# include <experimental/optional>
namespace std
{
using namespace experimental;    
}
#else
#error !
#endif

int main()
{
    std::optional< int > o;
    return 0;
}

引入 std::experimental "子命名空间" 的意图很明确,因为 std::experimental 目前包含 大量< strong>新的库。我认为很可能所有这些库都将在不做任何实质性更改的情况下迁移到 namespace std,当前编写的用户代码可以依赖于此(我完全错了吗?)。否则,所有这些代码都应该在未来进行重构,从 std::experimental :: 更改为std :: 。这并不是大问题,但可能有不这样做的理由。

问题涉及生产代码和不太严肃的代码。


1
我们在谈论可移植的生产代码吗? - MikeMB
@MikeMB 说,我们正在谈论一个广泛使用的开源大型项目(与人类生命安全无关)。 - Tomilov Anatoliy
3
[C++命名空间.std]:“如果没有特别说明,C++程序在将声明或定义添加到命名空间std或命名空间内的命名空间时,其行为是未定义的。” - user657267
4
@Orient 为什么要冒这个风险呢,只需要做类似这样的事情namespace xp = std::experimental,然后在实验版被采用时替换为 std 即可。 - user657267
@user657267,我特意询问您是否能以尽可能有根据的方式接受或拒绝这种方法。 - Tomilov Anatoliy
显示剩余3条评论
4个回答

11

在我的工作中,我花费了很多时间来对抗这种推测性复杂性(我正在寻找一个能描述这种行为的好词语,这是目前我想到的最好的一个词语)。

在我看来,你现在正在将复杂性和风险引入到你的代码中,以避免将来进行重构。这已经够糟糕了,但在这个特定的情况下,我甚至会说重构是一个不恰当的词语——这不仅仅是重构,而仅仅是简单的文本替换。

通过查看代码来去除std::experimental(或将其更改为std::或std::something_else),实际上只是一种文本替换。在最好的情况下,您只需要使用编辑器或IDE中的快速命令。在最坏的情况下,您可能需要花费几个小时编写正则表达式-也许是在您的编辑器中,也可能在PERL或Ruby中......

那些std::experiment表明您正在使用实验功能,并且有一个明确的表示该效果的声明在您的代码中是很好的。如果某些库进入标准,一位有能力的程序员可以快速轻松地进行必要的文本替换。如果您的文本编辑技能不够,不要破坏语言-提高您的文本编辑技能,这是一个机会。

总之,编写最简单,最干净的代码来满足您现在的需求,并随时准备根据情况进行更改。这通常会导致更灵活的代码,更好地支持您真正的未来需求,而不是现在的推测性预测。


8
听起来不太好。
首先,这是未定义行为。标准草案N4140说:
“[namespace.std]/1:如果未另行指定,则C++程序的行为未定义,如果它向命名空间std或命名空间std中的命名空间添加声明或定义。[...]”
使用指令是一种声明,因此UB是当天的命令。
其次,std::experimental中的内容非常容易改变。您可能会发现,当事物移动到std适当时,您的代码仍然可以编译,但并不完全以相同的方式运作。这只是在生产代码中寻找麻烦。

你甚至不需要走那么远。using-directive 是一个声明。 - T.C.

2
许多在std::experimental中的库在迁移到std之前会以一种会破坏用户代码的方式进行更改,甚至可能不会迁移到std。 这就是为什么它们被放在std::experimental中的原因。 std::experimental旨在成为一个相对自由的地方,您可以引入新的C ++库特性提案,编译器可以实现它们,而不会破坏现有代码。这些实现正在变化中,不是标准的。其中一些可能会进入C++1z,但其中一些可能不会,并且进入的那些可能会发生变化,而未进入的那些可能会在C++2x中进行重大更改。
只需看看例如Ranges的历史记录。或微软提出的coroutine / resumable函数内容。或反射工作组。或概念。
这个版本的C ++的目标是,敢于说,要敏捷,并且要快速失败。许多独立的提案通过流程工作,目标是最小化互依性。如果某个提案在C ++标准发布时还没有准备好,它就不会被采纳。如果它准备好了并且值得,它将模块化添加进去。
据我所知,这是为了避免某个过程变得“太大而无法失败”,并且未准备好的内容被发布到标准中,或者标准发布因某些原因而延迟多年。
除了上述之外,以那种方式操纵std会使您的程序不符合规范,而不需要进行诊断,正如其他答案所指出的那样。

1
你正在做的事情会引入未定义的行为。一般来说,我认为引入未定义的行为更多地属于不良实践范畴而不是良好实践范畴。
根据1998年的C++标准,第17.4.3.1节,第1段。
“在未特别说明的情况下,向命名空间std或命名空间std中的命名空间添加声明或定义是未定义的。程序可以为任何标准库模板添加模板特化到命名空间std中。标准库模板的这种特化(完全或部分)将导致未定义的行为,除非声明依赖于具有外部链接的用户定义名称,并且除非该特化满足原始模板的标准库要求。”
我没有更多最新版本的标准(在我的当前计算机上),但是从记忆中,所有C++标准的发布都有类似的条款。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接