我想有很多方法可以做到这一点。
如果你至少可以使用 C++14,我建议使用 decltype() 和 std::tuple_cat() 的强大功能,如下所示:
(1) 声明(没有定义的理由,因为通过decltype() 使用了几个重载(和SFINAE 启用/禁用)如下
template <std::size_t Imin, std::size_t Imax, std::size_t I, typename T>
std::enable_if_t<(Imin <= I) && (I < Imax), std::tuple<T>> getTpl ();
template <std::size_t Imin, std::size_t Imax, std::size_t I, typename>
std::enable_if_t<(I < Imin) || (Imax <= I), std::tuple<>> getTpl ();
这个想法是当索引在正确的范围内时返回std::tuple<T>,否则返回std::tuple<>。
(2) 定义一个帮助类将std::tuple<Ts...> 转换为TypeA<Ts...>
template <typename>
struct pta_helper2;
template <typename ... Ts>
struct pta_helper2<std::tuple<Ts...>>
{ using type = TypeA<Ts...>; };
(3) 定义一个辅助类,它只在一个元组中连接正确范围内的类型
template <std::size_t, std::size_t, typename ... Ts>
struct pta_helper1;
template <std::size_t I0, std::size_t I1, std::size_t ... Is, typename ... Ts>
struct pta_helper1<I0, I1, std::index_sequence<Is...>, Ts...>
: public pta_helper2<decltype(std::tuple_cat(getTpl<I0, I1, Is, Ts>()...))>
{ };
这个想法是连接std::tuple<>和std::tuple<T>的序列,其中T类型是请求范围内的类型;结果类型(pta_helper2 的模板参数)是 std::tuple<Us...>,其中 Us... 正是请求范围内的类型。
(4) 定义一个using 类型以更简单的方式使用前面的辅助类
template <std::size_t I0, std::size_t I1, typename ... Ts>
using proTypeA = typename pta_helper1<
I0, I1, std::make_index_sequence<sizeof...(Ts)>, Ts...>::type;
(5) 现在你的TypeB 变成了
template <typename ... Ts>
struct TypeB : public proTypeA<0u, sizeof...(Ts)/2u, Ts...>,
public proTypeA<sizeof...(Ts)/2u, sizeof...(Ts), Ts...>
{ };
以下是完整编译的 C++14 示例示例
#include <tuple>
#include <type_traits>
template <typename ...>
struct TypeA
{ };
template <std::size_t Imin, std::size_t Imax, std::size_t I, typename T>
std::enable_if_t<(Imin <= I) && (I < Imax), std::tuple<T>> getTpl ();
template <std::size_t Imin, std::size_t Imax, std::size_t I, typename>
std::enable_if_t<(I < Imin) || (Imax <= I), std::tuple<>> getTpl ();
template <typename>
struct pta_helper2;
template <typename ... Ts>
struct pta_helper2<std::tuple<Ts...>>
{ using type = TypeA<Ts...>; };
template <std::size_t, std::size_t, typename ... Ts>
struct pta_helper1;
template <std::size_t I0, std::size_t I1, std::size_t ... Is, typename ... Ts>
struct pta_helper1<I0, I1, std::index_sequence<Is...>, Ts...>
: public pta_helper2<decltype(std::tuple_cat(getTpl<I0, I1, Is, Ts>()...))>
{ };
template <std::size_t I0, std::size_t I1, typename ... Ts>
using proTypeA = typename pta_helper1<
I0, I1, std::make_index_sequence<sizeof...(Ts)>, Ts...>::type;
template <typename ... Ts>
struct TypeB : public proTypeA<0u, sizeof...(Ts)/2u, Ts...>,
public proTypeA<sizeof...(Ts)/2u, sizeof...(Ts), Ts...>
{ };
int main()
{
using tb = TypeB<char, short, int, long, long long>;
using ta1 = TypeA<char, short>;
using ta2 = TypeA<int, long, long long>;
static_assert(std::is_base_of<ta1, tb>::value, "!");
static_assert(std::is_base_of<ta2, tb>::value, "!");
}