Мне очень понравился этот вопрос и обсуждения вокруг него, особенно решение от T. C (у меня нет 50 комментариев, поэтому я буду публиковать комментарии в качестве другого решения). Я только что перешел из аналогичной ситуации, когда нужна пара, но также нужна библиотека для работы на C ++ 17 и C ++ 20.
Это решение от T. C. работает как для c ++ 17, так и для c ++ 20.
template<class P>
concept bool Pair = requires(P p) {
typename P::first_type;
typename P::second_type;
p.first;
p.second;
requires my_same_as<decltype(p.first), typename P::first_type>;
requires my_same_as<decltype(p.second), typename P::second_type>;
};
, где my_same_as
определяется как std::same_as
из c ++ 20:
template<class Me, class Other>
concept bool my_same_as = std::is_same_v<Me, Other> && std::is_same_v<Other, Me>;
Имею пробовал несколько «реализаций пар», и интересным моментом является то, что поля first
и second
могут отличаться от ссылочных или нереферентных типов.
T. C. упомянул, что мы могли бы заменить поля на:
{ p.first } -> my_same_as<typename P::first_type&>;
{ p.second } -> my_same_as<typename P::second_type&>;
Я обнаружил, что это работает только на c ++ 20, как ни странно, не на c ++ 17 (прекрасно компилируется, но не соответствует концепции!) , Каким-то образом он не соответствует ни ссылочным, ни ссылочным (требуется сложная реализация с ||
и std::remove_reference_t
).
Одно портативное решение, которое я нашел для c ++ 17 и c ++ 20 было:
template<typename P>
concept bool Pair = requires(P p)
{
typename P::first_type;
typename P::second_type;
{ p.first } -> my_convertible_to<typename P::first_type>;
{ p.second } -> my_convertible_to<typename P::second_type>;
};
, где my_convertible_to
эквивалентно std::convertible_to
из c ++ 20:
template <class From, class To>
concept bool my_convertible_to =
std::is_convertible_v<From, To> &&
requires(std::add_rvalue_reference_t<From> (&f)()) {
static_cast<To>(f());
};
Я не могу объяснить, почему это тонкое поведение изменилось с c ++ 17 на c ++ 20 (на is_same_v
logi c), но я публикую здесь, так как это может помочь другим в аналогичной ситуации. Я использовал g ++ - 8 для c ++ 17 и g ++ - 10.1 для c ++ 20. Спасибо за все обучение!