1

C++17 将(可能)放宽循环范围的定义,允许end()返回不同的类型(例如哨兵):

struct MyRange {
    struct Sentinel {};
    int* begin();
    Sentinel end();
};
bool operator!=(int*, MyRange::Sentinel);

目前支持此功能的唯一编译器是 gcc 6.1 和 clang 4.0+(示例)(错误消息示例)。如果我正在编写一个范围类型,其中哨兵​​对结束类型更有效,我如何检测编译器是否支持宽松范围?我在 P0184R0(上面链接)中看不到任何关于此的讨论;会提供功能测试宏吗?

进一步的问题:

  • 如果有办法检测编译器支持,那么更改end()成员函数的返回类型是否安全(对于库而言)?我是否需要让我的哨兵隐式转换为我的迭代器类型?
  • 相反,对于 C++17 之前的编译器,是否值得以不同的名称(例如sentinel())公开我的哨兵?C++17 之前的算法可以有效地使用[begin(), sentinel())还是不值得额外的代码?
4

2 回答 2

3

根据P0096R3,您可以检查是否__cpp_range_based_fo‌​r大于或等于 201603。当然,Visual Studio 不支持任何功能测试宏,因此您必须单独检查其版本控制。他们在 VS2015 Update 3 中提供了对它的支持,但与大多数其他 C++17 支持一起,您必须使用该/std:c++latest开关。

于 2016-08-16T14:06:58.223 回答
2

哨兵高效的原因很少与哨兵的内部状态有关。

因此,一种方法是提供Sentinel足够的内部状态来生成自身的迭代器版本。

即使在具有统一结束循环和算法的 C++14 中for(:),坚持相同的开始/结束迭代器类型,手写算法或循环也可以使用您的哨兵并提高效率。

如果您想要最大的覆盖率,像Boost.Config这样的库通常是您的最佳选择,但截至目前(我可以找到)尚未发布 C++17 功能检测集。

据我所知,没有办法 SFINAE 检测for(:)接受不同开始/结束迭代器类型的循环的存在。(我可以想象一些constexpr除了黑客之外的东西,但这超出了我的技能。)

检测是否<algorithms>接受哨兵结束迭代器可能可以使用 SFINAE 完成。但是我不确定即使 C++17 是否已经哨兵化<algorithms>甚至打算这样做;范围-v3 应该处理的返工。

于 2016-08-15T15:04:20.583 回答