2

我喜欢跨度,所以我gsl::span在这里和那里使用。但是 - 在 C++20 中,它将std::span改为*。我使用std::optional,但对于 C++14 代码,它需要是std::experimental::optional. 等等。

在这些变体(有时可能超过两个)之间进行编译时选择的惯用且面向未来的方法是什么,以便我的实际代码可以只使用一个标记序列,该标记序列编译为正确选择跨度,或可选,或其他类似的构造?

注意:我想避免污染全局命名空间。


* 好吧,从技术上讲,我也可以gsl::span稍后使用,但这个问题的想法是在标准可用时使用标准中的内容,并在此之前使用最接近的替代方案。

4

4 回答 4

2

我通常使用这样的东西:

#if some_kind_of_test_here_not_necessarily_a_macro
namespace stdx = std;
#elif some_other_test_here
namespace stdx = std::experimental;
#else
#error "Some Message"
#endif

现在在您的代码中使用:

stdx::span  mySpan;
于 2018-10-04T19:08:30.137 回答
1

这个问题是错误的,因为即使有这样一个“令牌序列”,也不能保证这两个备选方案的行为相同。

考虑experimental::optionalstd::optional.. 后者,在 C++17 的缺陷报告之后,如果可简单复制,则需要T可简单复制。experimental::optional不是。如果你依赖它来构建 C++17,你不知道它是否适用于 C++14。

gsl::span问题不大,因为 GSL 实现可能会跟踪更改,std::span因为它被合并到 C++20 中。

但是,如果您坚持这一点,C++20 将使功能测试宏成为强制性的。所以你可以使用这样的宏技术:

#include <version>
#ifdef <insert span test macro here>
#include <span>
template<typename T, std::ptrdiff_t N>
using span = std::span<T, N>;
#else
#include <gsl/span>
template<typename T, std::ptrdiff_t N>
using span = gsl::span<T, N>;
#endif

当然,这里的问题是你必须包含<version>,它本身就是一个 C++20 头文件。因此,此代码仅适用于至少部分兼容 C++20 的编译器。

于 2018-10-04T19:17:52.877 回答
0

@MartinYork 方法的一种改编,它(希望)在单一构造级别而不是整个命名空间级别上工作:

#if __cplusplus >= 202001L
#include <span>
namespace stdx {
template <class ElementType, std::ptrdiff_t Extent = std::dynamic_extent>
using span = std::span<ElementType, Extent>;
} // namespace stdx
#else
#include <gsl/span>
namespace stdx {
template <class ElementType, std::ptrdiff_t Extent = gsl::dynamic_extent>
using span = std::span<ElementType, Extent>;
} // namespace stdx
#endif // __cplusplus >= 202001L
于 2018-10-04T19:20:02.413 回答
0

一种方法是在迁移命名空间中使用包含合适using别名的迁移标头,例如:

#if __cplusplus < 201402L
#include <experimental/optional>
namespace mig {
    template <typename T>
    using optional = std::experimental::optional<T>;
}
#else
#include <optional>
namespace mig {
    template <typename T>
    using optional = std::optional<T>;
}
#endif

在迁移时,您将包含相应的标头并用于您的代码,该代码使用-du-jourmig::optional<T>与其他代码愉快地交互。optional一旦兼容性问题消失,您可以在合适的时候替换您的自定义资格。但是请注意,这些定义之间存在一些差异,即您需要坚持通用功能。

于 2018-10-04T19:16:18.250 回答