Цикл понятий C++

Я хотел бы попросить компилятор проверить, содержит ли кортеж только «метатипы».

Кстати, я совершенно новичок в концепциях С++.

template < typename T >
struct Type {
  using type = T;
};

//! A type can be easily check with a small concept
template < typename T >
concept bool  C_Type = requires {
  typename T::type;
};

//! But how to apply it on a whole tuple?
template < typename T >
void foo(T tuple) {}

int main() {

  constexpr auto  test = std::make_tuple(Type<int>{}, Type<double>{});
  foo(test);
}

Поэтому я хочу быть уверен, что каждый тип внутри последовательности (скажем, только что-то Iterable для этого примера) является «метатипом».

Я использую Boost Hana, если это может упростить код.

На данный момент я даже не уверен, что это возможно. Я надеюсь, что это так, я думаю, мне просто нужно узнать больше о метапрограммировании. Так что я буду продолжать искать и пробовать, но если у кого-то уже есть ответ, спасибо!


person Mathieu Van Nevel    schedule 05.09.2017    source источник
comment
Вопрос: как бы вы использовали T tuple? Какие ограничения вы на него накладываете? Это должно быть std::tuple? Если это так, используйте std::tuple_element, если нет, определите свои собственные черты и ограничения... Обратите внимание, что std::tuple_element также обрабатывает std::array и std::pair, поэтому, возможно, вы могли бы ожидать, что любой T также будет специализироваться на использовании foo. В противном случае вы можете попробовать использовать decltype(std::get<I>(tuple)) или как бы вы ни обращались к своим элементам кортежа.   -  person BeyelerStudios    schedule 05.09.2017
comment
Вы явно не используете текущую версию понятий, поскольку, насколько мне известно, concept bool в этой версии понятий нет. О какой именно версии вы спрашиваете?   -  person Yakk - Adam Nevraumont    schedule 05.09.2017
comment
@Yakk Ну, я читаю en.cppreference.com/w/cpp/language/constraints и используя Gcc 7.1, поэтому я думал использовать последний.   -  person Mathieu Van Nevel    schedule 05.09.2017
comment
@BeyelerStudios Вы заставили меня понять, что std::tuple не может пройти каждый элемент один за другим... Я всегда использую hana::tuple и совершенно забываю, что они не совпадают... Мне нужно отредактировать это вопрос наверное. Но я всегда буду пытаться проверить последовательность Типа, я думаю.   -  person Mathieu Van Nevel    schedule 05.09.2017
comment
Вы можете просмотреть каждый элемент вариативного шаблона (constexpr или нет) с помощью рекурсии, см. stackoverflow.com/a/38776200/3426025   -  person BeyelerStudios    schedule 05.09.2017
comment
@BeyelerStudios Да, я слишком привык использовать Hana, поэтому начал забывать, как она работает внутри. Я должен быть в состоянии получить что-то с этим в виду. Пойду спать немного раньше, но спасибо за помощь :)   -  person Mathieu Van Nevel    schedule 05.09.2017
comment
stackoverflow.com/ вопросы/45563975/   -  person Jason Rice    schedule 06.09.2017
comment
Когда дело доходит до работы с кортежеподобными типами в соответствии со стандартной моделью, интерфейс для программирования (мета- или иным образом) состоит из std::tuple_element, std::tuple_size и std::get. Использование индексов является основным в этих обстоятельствах.   -  person Luc Danton    schedule 06.09.2017


Ответы (3)


Концепции изначально слишком слабы для выполнения метапрограммирования, поэтому для этого вам потребуется некоторая «метапрограммирующая помощь» от остальной части языка. Я бы использовал специализацию шаблона, чтобы разложить тип на шаблон и его параметры типа, а затем потребовал, чтобы все эти параметры удовлетворяли C_Type:

template <class>
constexpr bool TypeTuple_ = false;
template <template <class...> class Tuple, class... Types>
  requires (C_Type<Types> && ...)
constexpr bool TypeTuple_<Tuple<Types...>> = true;

template <class T>
concept bool TypeTuple = TypeTuple_<T>;

Это работает с hana::tuple и std::tuple — любым шаблоном, который принимает все параметры типа.

person Casey    schedule 05.09.2017
comment
concept bool все еще в TS? (спрашивая из-за предыдущего комментария к ОП) - person Jason Rice; 06.09.2017
comment
@jasonrice TS был опубликован и в основном является окончательным, так что да. Однако этого нет в рабочем документе C++20. Wg21 удалила bool из синтаксиса понятий в Торонто. - person Casey; 06.09.2017

Я не очень хорошо разбираюсь в концепциях, но вы, безусловно, можете добиться этого с помощью Boost.Hana несколькими способами.

Глядя на комментарии, следует отметить, что любой тип кортежа может быть преобразован в hana::Sequence, который по соглашению также является hana::Searchable и hana::Foldable.

Вот пример с std::tuple, используемым как hana::Searchable:

#include <boost/hana.hpp>
#include <boost/hana/ext/std/tuple.hpp>
#include <tuple>
namespace hana = boost::hana;

template < typename T >
concept bool  C_Type = requires {
  typename T::type;
};

auto is_C_Type = hana::overload_linearly([](C_Type const&) { return hana::true_c; },
                                         [](auto const&)   { return hana::false_c; });

template < typename T >
constexpr bool foo(T const& tuple) {
  return hana::all_of(tuple, is_C_Type);
}

int main() {
  constexpr auto  test = std::tuple{hana::type_c<int>, hana::type_c<double>};
  static_assert(foo(test));
}

https://wandbox.org/permlink/YNZDX7uN6mgUdmje

person Jason Rice    schedule 05.09.2017

Вот пример того, как вы можете проверить, содержит ли tuple только типы, определяющие имя типа type. Хитрость заключается в том, чтобы определить тип кортежа, который определяет новый тип std::pair<std::pair<...std::pair<void, T0>, ...TN>, TM> для кортежа std::tuple<T0, ..., TN, TM>. Этот работает в GCC 7.2. Мне было бы интересно, как еще один четко сочетает вариативные ограничения, поскольку я не нашел никаких ссылок.

#include <array>
#include <tuple>

template<typename T>
struct Type {
    using type = T;
};

template<typename Tuple, size_t I = std::tuple_size<Tuple>::value>
struct TupleType {
    using type = std::pair<typename TupleType<Tuple, I - 1>::type,
                           typename std::tuple_element<I - 1, Tuple>::type>;
};

template<typename Tuple>
struct TupleType<Tuple, 0> {
    using type = void;
};

template<typename T>
concept bool C_TupleType = requires {
    typename TupleType<T>::type;
};

void foo(C_TupleType tuple) { }

int main() {
    constexpr auto test = std::make_tuple(Type<int>{}, Type<double>{});
    foo(test);

    // also works on pair and array
    constexpr auto test1 = std::make_pair(Type<int>{}, Type<double>{});
    foo(test1);
    constexpr std::array<Type<int>, 3> test2;
    foo(test2);

    // and of course TupleType is also a meta type
    constexpr std::array<TupleType<std::pair<int, int>>, 13> test3;
    foo(test3);

    return 0;
}
person BeyelerStudios    schedule 05.09.2017