Reputation: 1486
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!
Upvotes: 2
Views: 687
Reputation: 42554
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.
Upvotes: 3
Reputation: 1696
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
Upvotes: 2
Reputation: 4283
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;
}
Upvotes: 1