如何用参数数量定义 std::tuple<...>

How to define std::tuple<...> with number of arguments

我需要与在表单上使用(误用)元组的代码交互:

using Tuple = std::tuple<double, double, double, double, int, int, int, int>; // etc..

我想知道是否有一种方法可以使用模板而不是以下形式来定义此元组:

using Tuple = SomeType<4, double, 4, int>::Type; // expands to the above tuple

并指定参数的数量而不是指定每个类型。

我宁愿只使用 std 库,但可以接受 boost。我需要它与 c++14 一起工作。用宏很容易做到,但是我已经有了宏的解决方案,我不喜欢在代码中为这种代码添加宏。

上面的元组是一个小例子。实际上,元组要大得多,包含更多类型,并且每种类型更多。

我不知道某些 std 设施可以直接执行您想要的操作。

棘手的部分是拥有一个混合了非类型和类型参数的可变参数模板。使用助手可以避免此问题:

template <typename T,size_t reps>
struct repeated_type {
    using type = T;
    static const size_t N = reps;
};

用法可能如下所示:

int main() {
    using two_ints = repeated_type<int,2>;
    using three_doubles = repeated_type<double,3>;
    using my_tuple = n_tuple<two_ints,three_doubles>;
    static_assert(std::is_same<
                         std::tuple<int,int,double,double,double>,
                         my_tuple
                  >::value);
}

使用 std::index_sequence we can get a std::tuple<T,T,T,...T> via std::make_tuple

template <typename T,std::size_t...n>
auto n_tuple_impl(std::index_sequence<n...>){ 
    return std::make_tuple( (n,T{})...); 
}

template <typename repT>
using n_tuple_single = decltype( 
                           n_tuple_impl<typename repT::type>(
                               std::make_index_sequence<repT::N>() 
                           )
                       );

可以通过 std::tuple_cat:

连接其中的几个
template <typename...repT>
using n_tuple = decltype( 
                    std::tuple_cat( 
                        ( n_tuple_single<repT>() )... 
                    ) 
                );

Live Demo.

在两个地方我需要默认构造。如果需要,这可以通过 std::declval 规避。实际上没有创建任何实例。

对于感兴趣的 reader,here 是一个相当混乱的 C++11 实现,它基于递归而不是 std::index_sequence 和折叠表达式来实现相同的目的。

这是一个使用 Boost.MP11 的简短解决方案,可以与任何类型的列表持有者一起使用(例如 std::tupleboost::mp11::mp_list 等)。

#include <boost/mp11/algorithm.hpp>

#include <cstddef>
#include <tuple>
#include <type_traits>

template<class T, std::size_t N, template<class...> class THolder = std::tuple>
struct repeater {
    using type = boost::mp11::mp_repeat_c<THolder<T>, N>;
};

template<class T, std::size_t N>
using repeater_t = typename repeater<T, N>::type;

int main() {
    using expected_t = std::tuple<double, double, double, double, int, int, int, int>;
    using actual_t = boost::mp11::mp_append<repeater_t<double, 4>, repeater_t<int, 4>>;
    static_assert(std::is_same_v<actual_t, expected_t>);
}

在这里,我们利用 boost::mp11::mp_repeat_c 构建持有 N 类型 T 类型的类型持有者。根据要求,我们默认的类型列表是 std::tuple 。然后,在调用站点,只需通过 boost::mp11::mp_append 将元组附加在一起即可得到一个元组。

Wandbox link