Какой идиоматический способ ссылаться на std :: what или not_yet_in_std :: what?

Мне нравятся пролеты, поэтому я использую gsl::span здесь и там. Но — в C ++ 20 это будет std::span вместо*. я использую std::optional, но для кода C ++ 14 это должно быть std::experimental::optional, И так далее.

Какой идиоматичный и своего рода перспективный способ сделать выбор во время компиляции между этими вариантами (иногда, возможно, более двух), так что мой реальный код может просто использовать одну последовательность токенов, которая компилируется в правильно выбранный span или опционально, или другая подобная конструкция?

Примечание. Я хочу избежать загрязнения глобального пространства имен.


* Ну, технически я мог бы использовать gsl::span позже, но идея в этом вопросе состоит в том, чтобы использовать то, что в стандарте, как только это будет доступно, и ближайшую альтернативу, до этого.

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;
2

Другие решения

Этот вопрос ошибочен, потому что, даже если бы существовала такая «последовательность токенов», нет никакой гарантии, что эти две альтернативы вести себя тот же самый.

Рассматривать experimental::optional против std::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.

1

Одним из подходов является использование заголовка миграции, содержащего подходящий 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

При переносе вы должны включить соответствующий заголовок и использовать mig::optional<T> для вашего кода, который успешно взаимодействует с другим кодом, используя optional-du-Жур. Как только проблема совместимости исчезнет, ​​вы сможете заменить свою специальную квалификацию в любое время. Однако обратите внимание, что между этими определениями есть некоторые различия, т. Е. Вам нужно придерживаться общей функциональности.

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
0
По вопросам рекламы [email protected]