2

I'd like to ask the compiler to check if a tuple contain only "meta types".

By the way I'm completely new with C++ concepts.

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);
}

So I want to be sure that every type inside the sequence (let's say only something Iterable for this example) is a "meta type".

I'm using Boost Hana if it can simplify the code.

At the moment I'm not even sure if it's possible. I hope it is, I guess I just need to learn more meta-programming stuff. So I'll continue to search and try, but if somebody already has the answer, thanks!

Mathieu Van Nevel
  • 1,428
  • 1
  • 10
  • 26
  • 1
    Question is: how would you use `T tuple`? What constraints do you put on it? Must it be a `std::tuple`? If so, use `std::tuple_element`, if not define your own traits and constraints... Note that `std::tuple_element` also handles `std::array` and `std::pair`, so maybe you could expect any `T` to specialise it as well to use `foo`. Otherwise you might want to try using `decltype(std::get(tuple))` or however you access your tuple elements. – BeyelerStudios Sep 05 '17 at 20:07
  • You are clearly not using the current version of concepts, as `concept bool` is gone in that version of concepts as far as I know. Which version are you asking about, specifically? – Yakk - Adam Nevraumont Sep 05 '17 at 20:11
  • @Yakk Well I'm reading http://en.cppreference.com/w/cpp/language/constraints and using Gcc 7.1 so I was thinking to be on the last one. – Mathieu Van Nevel Sep 05 '17 at 20:13
  • @BeyelerStudios You make me realize that std::tuple has no way to go through each element one by one... I always use hana::tuple and I completlty forget they aren't the same... I need to edit this question I guess. But I will always try to check a sequence of Type I guess. – Mathieu Van Nevel Sep 05 '17 at 20:16
  • 2
    You can "go through each element" of a variadic template (`constexpr` or not) using recursion, see https://stackoverflow.com/a/38776200/3426025 – BeyelerStudios Sep 05 '17 at 20:28
  • @BeyelerStudios Right, I was getting to much used to use Hana so I started to forgot how it was working inside. I should be able to get something with that in mind. I'll go sleep a little before, but thanks for the help :) – Mathieu Van Nevel Sep 05 '17 at 20:33
  • https://stackoverflow.com/questions/45563975/how-to-remove-metaprogramming-recursion-with-boost-hana – Jason Rice Sep 05 '17 at 22:13
  • 1
    When it comes to working with tuple-like types following the Standard model, the interface to program (meta- or otherwise) against is made up of `std::tuple_element`, `std::tuple_size`, and `std::get`. Using [indices](https://stackoverflow.com/questions/31463388/can-someone-please-explain-the-indices-trick) is a staple in these circumstances. – Luc Danton Sep 06 '17 at 17:36

3 Answers3

3

Concepts are by design too weak to perform metaprogramming, so to do this you need some "metaprogramming help" from the rest of the language. I would use template specialization to decompose a type into a template and its type parameters, and then require all of those parameters to satisfy 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>;

This works with hana::tuple, and std::tuple - any template that takes all type parameters.

Casey
  • 41,449
  • 7
  • 95
  • 125
  • 1
    Is the `concept bool` still in the TS? (asking because of a previous comment on the OP) – Jason Rice Sep 05 '17 at 23:58
  • 3
    @jasonrice The TS has been published and is basically final, so yes. It's not in the C++20 working paper, though. Wg21 removed the "bool" from concept syntax in Toronto. – Casey Sep 06 '17 at 02:21
2

I'm not too familiar with concepts, but you can certainly achieve this with Boost.Hana in a number of ways.

From looking at the comments, it should be noted that any tuple type can be made into a hana::Sequence which by convention is also hana::Searchable and hana::Foldable.

Here is an example with std::tuple used as a 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

Jason Rice
  • 1,686
  • 1
  • 12
  • 17
1

Here is an example of how you could check if tuple only holds types that define a typename type. The trick here is to define a tuple type that defines a new type std::pair<std::pair<...std::pair<void, T0>, ...TN>, TM> for the tuple std::tuple<T0, ..., TN, TM>. This works in GCC 7.2. I'd be interested on how one more cleanly combines variadic constraints as I didn't find any references.

#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;
}
BeyelerStudios
  • 4,243
  • 19
  • 38