Are there any reasons why c++ template packs are passed using std::tuple

时光毁灭记忆、已成空白 提交于 2019-12-12 18:51:39

问题


Let's say we want to create a helper class to reverse template pack e.g. as follows:

#include <tuple>
#include <utility>
#include <typeinfo>
#include <iostream>

template <class>
struct sizer;

template <template<class...> class Pack, class... Args>
struct sizer<Pack<Args...>> {
   static constexpr size_t value = sizeof...(Args);
};

template <class Pack, class Indices = std::make_index_sequence<sizer<Pack>::value>>
struct reverse_pack;

template <class... Args, size_t... I>
struct reverse_pack<std::tuple<Args...>, std::integer_sequence<std::size_t, I...>> {
    using type = typename std::tuple<typename std::tuple_element<(sizeof...(Args) - I - 1), std::tuple<Args...>>::type...>;
};

int main() {
   std::cout << typeid(reverse_pack<std::tuple<int, float, double>>::type).name() << std::endl;
}

We could successfully do exactly the same thing using e.g. function signature as a template parameter:

#include <utility>
#include <typeinfo>
#include <iostream>

template <class>
struct sizer;

template <class... Args>
struct sizer<void(Args...)> {
   static constexpr size_t value = sizeof...(Args);
};

template <size_t N, class Sign>
struct nth_param;

template <size_t N, class First, class... Args>
struct nth_param<N, void(First, Args...)>: nth_param<N-1, void(Args...)> { };

template <class First, class... Args>
struct nth_param<0, void(First, Args...)> {
   using type = First;
};

template <class Pack, class Indices = std::make_index_sequence<sizer<Pack>::value>>
struct reverse_pack;

template <class... Args, size_t... I>
struct reverse_pack<void(Args...), std::integer_sequence<std::size_t, I...>> {
    using type = void(typename nth_param<(sizeof...(Args) - I - 1), void(Args...)>::type...);
};

int main() {
   std::cout << typeid(reverse_pack<void(int, float, double)>::type).name() << std::endl;
}

My experience with std::tuple (e.g. here) shows its intended to store data rather than to pass packs of types between template. So are there any practical reasons to use a tuple to operate on variadics?


回答1:


So are there any practical reasons to use a tuple to operate on variadics?

A tuple doesn't perform any conversions on its arguments - a tuple<int[2]> indeed contains an int[2] as its first type, whereas a void(int[2]) is really a void(int*). The same holds for const, functions, and other types that undergo decay. That makes function a non-viable option.

If you wrote your own typelist (e.g. template <class... Ts> struct typelist{};), you would still have to reimplement std::get, std::tuple_element, and std::tuple_size. That's the nice thing about tuple - it comes ready and useful.

And everybody already knows what std::tuple is. Even if function signatures didn't decay their arguments in a way that would break, I would still use the type that's created to be a heterogeneous container of types - and not shoehorn your solution into something else that happens to work. Principle of least surprise and all.



来源:https://stackoverflow.com/questions/37550420/are-there-any-reasons-why-c-template-packs-are-passed-using-stdtuple

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!