P0040R3(adopted 2016-06,另请参见N4603)在草案中引入了诸如std::uninitialized_move_n
之类的扩展内存管理算法,最终成为ISO C ++ 17的一部分。其中一些参数带有额外的ExecutionPolicy
参数,可能会进一步支持并行性。
但是,截至目前(2018年8月),我还没有发现这些重载实现附带任何标准库实现。我检查过的实现文档并没有很好地阐明它。具体来说,(当前)它们是:
std::destroy_at
和std::uninitialized_move_n
而没有ExecutionPolicy
的版本在GCC 8.2中。ExecutionPolicy
的重载丢失了。/std:c++17
或/std:c++latest
的支持P0040R3,但实际上缺少ExecutionPolicy
的重载。我知道,唯一具有ExecutionPolicy
重载的实现是在HPX中,但这不是标准库的完整实现。如果要便携式使用这些功能,则必须同样适应自定义实现,而不是直接使用std
名称。但是我仍然希望将来使用std
实现作为首选项(除非他们有已知的错误)。 (原因是,实现定义的执行策略与具体的实现紧密结合,因此,外部实现及其客户端代码一般来说,利用各种执行策略的机会会更少;尽管对于客户端代码而言,这不一定是正确的。因此,我希望可以在我的适用的适应性自适应层中有条件地包含一些内容,以用于实现-在标准库提供using std::...
时获得指定的功能,并且补充我的实现,因为只有在必要时才从标准库实现中退回缺少的部分。
如我所知,SD-6 feature testing macros和P0941R2显示__cpp_lib_raw_memory_algorithms
对于P0040R3中的功能已经足够。另一方面,__cpp_lib_parallel_algorithm
似乎与<memory>
根本无关。因此,无法像当前的libc ++和MSVC实现那样表达状态-使用P0040R3中的std
名称,但缺少ExecutionPolicy
重载。而且我不确定__has_include<execution>
是否能正常工作。现实可能更奇怪,例如P0336R1甚至是not supported by libc++。
因此,当功能(希望)在某些较新版本的标准库实现中可用时,如何使它们完美地移植到我的代码中,除了检查它们的每个版本的来源之外,或者完全重塑了整个P0040R3的车轮?
编辑:
我知道功能测试宏的预期用途,并且我认为libstdc ++做对了。但是,仍有改进的空间。更具体地说,我的可移植层代码将扮演实现的角色(例如HPX),但在标准库实现已提供轮子的情况下,它们的意义就更轻巧,而不是重新发明轮子:
namespace my
{
#if ???
//#if __cpp_lib_raw_memory_algorithms
using std::uninitialized_move_n;
// XXX: Is this sufficient???
#else
// ... wheels here ... not expected to be more efficient to std counterparts in general
#endif
}
所以我的客户代码可以是:
my::uninitialized_move_n(???::par, iter, size, d_iter);
而不是(从巴里的回答中复制):
#if __cpp_lib_raw_memory_algorithms
std::uninitialized_move_n(std::execution::par, iter, size, d_iter);
#else
// ???
#endif
这两个代码段都可以工作,但是显然在客户端代码中的每个地方直接检查__cpp_lib_raw_memory_algorithms
的开销更大。
理想情况下,我应该具有一些完整的最新标准库实现,但是我不能保证总是如此(特别是在将标准库作为系统库的一部分安装的环境中使用)。无论如何,我需要进行调整以减轻客户的工作负担。
后退很明显:完全避免使用using std::uninitialized_move_n;
路径。恐怕这将是一种悲观的实现,因此我想尽可能避免使用这种方法。
第二次更新:
由于“ 完全可移植”听起来不清楚,因此我在上面的编辑中举例说明了一些代码。尽管问题没有改变,但标题仍然涵盖,但在这里我将使其更加具体。
我要在问题中使用的“完全可移植”的方式受到限制,因为在上述编辑等代码的情况下,填充了???
中标记的任何部分,而无需依赖任何特定版本的语言实现(例如,不应使用像宏名称依赖于实现的东西之类的东西。)
请参见here和here,以获取符合条件的代码示例失败。 (好吧,这些版本是通过检查提交日志来找出的……肯定是不完美的,在某些情况下还是 buggy 。)请注意,这与ExecutionPolicy
的重载无关,因为在提到的标准库实现中缺少它们,而我的下一个动作取决于此问题的解决方案。 (但是std
中名称的未来应该很清楚。)
一个完美(足够)的解决方案可以是,例如,添加一个新的功能测试宏以使重载独立于__cpp_lib_raw_memory_algorithms
,因此将来我可以仅使用ExecutionPolicy
添加重载的实现当独立的新功能测试宏未检测到它们时,又不会弄乱#if
的情况。但是我当然不能保证这种方式是可行的。这最终取决于委员会和供应商的决定。
我不确定是否可以有其他指示。
答案 0 :(得分:4)
P0941的初始版本包含一个表格,该表格清楚地表明P0040R3具有相应的功能测试宏__cpp_lib_raw_memory_algorithms
。这意味着正确编写代码以有条件地使用此功能的可移植方式是:
#if __cpp_lib_raw_memory_algorithms
std::uninitialized_move_n(std::execution::par, iter, size, d_iter);
#else
// ???
#endif
强加的要求是,如果定义了该宏,则该函数存在并执行标准规定的操作。但是,没有定义的宏实际上并没有说什么。如您所指出的那样,P0040R3的某些部分是在libstdc ++中实现的-部分但不是全部,这就是为什么未定义功能测试宏的原因。
当前,人们正在齐心协力在libstdc ++中实现并行算法。
关于在#else
分支中的操作,嗯...您有点自己。