Triangularizing a tuple

MTC*_*ter 5 c++ c++17

I’ve been trying to upgrade (and slightly adapt) this solution from 2012 using modern features of C++.

My goal is actually slightly simpler than in that question; I’d like this:

triangularize_t<T0, T1, ..., TN-1, TN>
Run Code Online (Sandbox Code Playgroud)

To be equivalent to this:

std::tuple<
  std::tuple<>,
  std::tuple<T0>,
  std::tuple<T0, T1>,
  ...
  std::tuple<T0, T1, ..., TN-1>
>

Run Code Online (Sandbox Code Playgroud)

Such that std::tuple_element_t<N, result> has N elements. The type TN should not appear anywhere in the output.

Here’s what I’ve worked up to so far:

template <class _Tuple, class _Seq>
struct _tuple_head;
template <class _Tuple, size_t... _N>
struct _tuple_head<_Tuple, std::index_sequence<_N...>> {
    using type = std::tuple<std::tuple_element_t<_N, _Tuple>...>;
};


template <class _Tuple, class _Seq>
struct _triangularize_impl;
template <class _Tuple, size_t... _N>
struct _triangularize_impl<_Tuple, std::index_sequence<_N...>> {
    using type = std::tuple<typename _tuple_head<_Tuple, std::make_index_sequence<_N>>::type...>;
};


template <class... _Pack>
struct triangularize {
    using type = _triangularize_impl<std::tuple<_Pack...>, std::index_sequence_for<_Pack...>>;
};


template <class... _Pack>
using triangularize_t = typename triangularize<_Pack...>::type;
Run Code Online (Sandbox Code Playgroud)

However, it doesn’t quite seem to be expanding the way I’d expect it to. Using triangularize_t<int, float> as a test, error messages seem to report that the output for std::get<0> and 1 return these types (identical for some reason).

_triangularize_impl<tuple<std::__1::tuple<int, float> >, __make_integer_seq<integer_sequence, unsigned long, 1UL> >

_triangularize_impl<tuple<std::__1::tuple<int, float> >, __make_integer_seq<integer_sequence, unsigned long, 1UL> >
Run Code Online (Sandbox Code Playgroud)

What have I missed here?

max*_*x66 3

也许有人可以用更简单的方式做到这一点......但是如下呢?

template <typename T, std::size_t ... Is>
auto gtt_helper (std::index_sequence<Is...>)
 -> std::tuple<std::tuple_element_t<Is, T>...>;

template <typename ... Ts, std::size_t ... Is>
auto getTriTuple (std::index_sequence<Is...>)
 -> std::tuple<decltype(gtt_helper<std::tuple<Ts...>>
                        (std::make_index_sequence<Is>{}))...>;

template <typename ... Ts>
using triTuple
  = decltype(getTriTuple<Ts...>(std::index_sequence_for<Ts...>{}));
Run Code Online (Sandbox Code Playgroud)

以下是完整编译C++14的例子

#include <type_traits>
#include <utility>
#include <tuple>

template <typename T, std::size_t ... Is>
auto gtt_helper (std::index_sequence<Is...>)
 -> std::tuple<std::tuple_element_t<Is, T>...>;

template <typename ... Ts, std::size_t ... Is>
auto getTriTuple (std::index_sequence<Is...>)
 -> std::tuple<decltype(gtt_helper<std::tuple<Ts...>>
                        (std::make_index_sequence<Is>{}))...>;

template <typename ... Ts>
using triTuple
  = decltype(getTriTuple<Ts...>(std::index_sequence_for<Ts...>{}));

int main () 
 {
   using T0 = triTuple<char, int, long, long long>;
   using T1 = std::tuple<std::tuple<>,
                         std::tuple<char>,
                         std::tuple<char, int>,
                         std::tuple<char, int, long>>;

   static_assert( std::is_same<T0, T1>::value, "!" );
 }
Run Code Online (Sandbox Code Playgroud)

为了回答你的问题(“我在这里错过了什么?”),你错过了 atypename::typeatriangularize

在我看来,正确的版本应该是

template <class... _Pack>
struct triangularize {
// ..........VVVVVVVV  add typename
using type = typename _triangularize_impl<std::tuple<_Pack...>,
                                          std::index_sequence_for<_Pack...>>::type ;
// and add ::type ..........................................................^^^^^^
};
Run Code Online (Sandbox Code Playgroud)

不幸的是,您的(更正后的)代码似乎适用于 clang++ 但不适用于 g++;我怀疑有 g++ bug,但我不确定。