Слишком поздно играть?
Извините, но ... почему бы вам просто не использовать шаблонное вычитание?
Что-то вроде
template <typename>
struct check_tuple;
template <template <typename...> class Tpl, std::uint32_t ... Is,
typename ... Ts>
struct check_tuple<Tpl<
std::pair<std::integral_constant<std::uint32_t, Is>, Ts>...>>
: public std::is_same<
std::integer_sequence<std::uint32_t, Is...>,
std::make_integer_sequence<std::uint32_t, sizeof...(Is)>>
{ };
Заметьте, что использование параметра template-template позволяет использовать его с std::tuple
, а также с boost::tuple
. [неправильно: см. Следующую редакцию]
Ниже приводится полная компиляция C ++ 14пример
#include <tuple>
#include <vector>
using T1 = std::tuple<
std::pair<std::integral_constant<std::uint32_t, 0>, std::vector<int>>,
std::pair<std::integral_constant<std::uint32_t, 1>, std::vector<double>>,
std::pair<std::integral_constant<std::uint32_t, 2>, std::vector<float>>
>;
using T2 = std::tuple<
std::pair<std::integral_constant<std::uint32_t, 0>, std::vector<int>>,
std::pair<std::integral_constant<std::uint32_t, 1>, std::vector<double>>,
std::pair<std::integral_constant<std::uint32_t, 1>, std::vector<float>>
>;
template <typename>
struct check_tuple;
template <template <typename...> class Tpl, std::uint32_t ... Is,
typename ... Ts>
struct check_tuple<Tpl<
std::pair<std::integral_constant<std::uint32_t, Is>, Ts>...>>
: public std::is_same<
std::integer_sequence<std::uint32_t, Is...>,
std::make_integer_sequence<std::uint32_t, sizeof...(Is)>>
{ };
int main()
{
static_assert( check_tuple<T1>::value == true, "!" );
static_assert( check_tuple<T2>::value == false, "!" );
}
- РЕДАКТИРОВАТЬ -
Я ошибся: boost::tuple
не определен как std::tuple
, получая список переменных типов шаблонов, но с фиксированным числом (10, но должно быть возможно изменить его) параметра шаблона типа, по умолчанию boost::tuples::null_type
.
Так, например,
using T1 = boost::tuple<
std::pair<std::integral_constant<std::uint32_t, 0>, std::vector<int>>,
std::pair<std::integral_constant<std::uint32_t, 1>, std::vector<double>>,
std::pair<std::integral_constant<std::uint32_t, 2>, std::vector<float>>
>;
имеет три std::pair
и семь boost::tuples::null_type
.
Другими словами, T1
using T1 = boost::tuple<
std::pair<std::integral_constant<std::uint32_t, 0>, std::vector<int>>,
std::pair<std::integral_constant<std::uint32_t, 1>, std::vector<double>>,
std::pair<std::integral_constant<std::uint32_t, 2>, std::vector<float>>,
boost::tuples::null_type,
boost::tuples::null_type,
boost::tuples::null_type,
boost::tuples::null_type,
boost::tuples::null_type,
boost::tuples::null_type,
boost::tuples::null_type
>;
Это нарушает мое предыдущее решение, потому что
template <template <typename...> class Tpl, std::uint32_t ... Is,
typename ... Ts>
struct check_tuple<Tpl<
std::pair<std::integral_constant<std::uint32_t, Is>, Ts>...>>
не перехватывает семьфиналы boost::tuples::null_type
.
Лучшее, что я могу себе представить для решения этой проблемы, - это преобразование типов boost::tuple
против std::tuple
, которое удаляет типы boost::tuples::null_type
.
Я имею в виду
template <typename T>
struct get_tuple
{ using type = std::tuple<T>; } ;
template <>
struct get_tuple<boost::tuples::null_type>
{ using type = std::tuple<>; };
template <typename ... Ts>
auto convert_tuple (boost::tuple<Ts...>)
-> decltype( std::tuple_cat(std::declval<typename get_tuple<Ts>::type>()...) );
Теперь check_tuple
можно переписать следующим образом
template <typename T,
typename = decltype(convert_tuple(std::declval<T>()))>
struct check_tuple;
template <typename BT, std::uint32_t ... Is, typename ... Ts>
struct check_tuple<BT, std::tuple<
std::pair<std::integral_constant<std::uint32_t, Is>, Ts>...>>
: public std::is_same<
std::integer_sequence<std::uint32_t, Is...>,
std::make_integer_sequence<std::uint32_t, sizeof...(Is)>>
{ };
Ниже приведен пример полной компиляции C ++ 14 с использованием boost::tuple
#include <tuple>
#include <vector>
#include "boost/tuple/tuple.hpp"
using T1 = boost::tuple<
std::pair<std::integral_constant<std::uint32_t, 0>, std::vector<int>>,
std::pair<std::integral_constant<std::uint32_t, 1>, std::vector<double>>,
std::pair<std::integral_constant<std::uint32_t, 2>, std::vector<float>>
>;
using T2 = boost::tuple<
std::pair<std::integral_constant<std::uint32_t, 0>, std::vector<int>>,
std::pair<std::integral_constant<std::uint32_t, 1>, std::vector<double>>,
std::pair<std::integral_constant<std::uint32_t, 1>, std::vector<float>>
>;
template <typename T>
struct get_tuple
{ using type = std::tuple<T>; } ;
template <>
struct get_tuple<boost::tuples::null_type>
{ using type = std::tuple<>; };
template <typename ... Ts>
auto convert_tuple (boost::tuple<Ts...>)
-> decltype( std::tuple_cat(std::declval<typename get_tuple<Ts>::type>()...) );
template <typename T,
typename = decltype(convert_tuple(std::declval<T>()))>
struct check_tuple;
template <typename BT, std::uint32_t ... Is, typename ... Ts>
struct check_tuple<BT, std::tuple<
std::pair<std::integral_constant<std::uint32_t, Is>, Ts>...>>
: public std::is_same<
std::integer_sequence<std::uint32_t, Is...>,
std::make_integer_sequence<std::uint32_t, sizeof...(Is)>>
{ };
int main()
{
static_assert( check_tuple<T1>::value == true, "!" );
static_assert( check_tuple<T2>::value == false, "!" );
}