给定std::tuple<A, B, ...> foo
,C ++ 14中是否有任何泛型(模板化)函数或技术来获得新的元组std::tuple<B, ...> bar
,该元组包含foo
的除第一个元素以外的所有元素?或者,也许是Boost中的某些东西?
我已经使用参数包和一些模板元编程编写了一个帮助程序函数,但是我很想把所有这些东西都扔掉!
这就是我目前正在做的事情。我定义了一个辅助函数unshift_tuple()
,该函数返回一个元组,该元组包含除传递给该函数的元组的第一个元素以外的所有元素。 unshift_tuple()
的实现使用辅助函数unshift_tuple_with_indices()
,该函数需要一个包含元组索引的参数包以进行提取; sequential_integer_list
帮助程序类型用于使用模板元编程来生成适当的索引列表参数包。丑!
#include <tuple>
template <size_t... Integers>
struct integer_list {};
template <size_t N, size_t... Args>
struct sequential_integer_list : sequential_integer_list<N - 1, N - 1, Args...> {};
template <size_t... Args>
struct sequential_integer_list<0, Args...> { typedef integer_list<Args...> type; };
template <typename FirstElement, typename... Elements, size_t... Indices>
static std::tuple<Elements...> unshift_tuple_with_indices(
const std::tuple<FirstElement, Elements...>& tuple,
integer_list<Indices...> index_type)
{
return std::make_tuple(std::get<Indices + 1>(tuple)...);
}
template <typename FirstElement, typename... Elements>
std::tuple<Elements...>
unshift_tuple(const std::tuple<FirstElement, Elements...>& tuple)
{
return unshift_tuple_with_indices(tuple,
typename sequential_integer_list<sizeof...(Elements)>::type());
}
int main(int, char *[])
{
std::tuple<int, std::string, double> foo(42, "hello", 3.14);
std::tuple<std::string, double> bar = unshift_tuple(foo);
}
要清楚,此代码可以正常工作。我非常希望删除它(或其中的任何部分),并尽可能使用内置的东西!
Jarod42指出了C ++ 14中std::integer_list
的存在,将实现简化为:
#include <cstddef>
#include <tuple>
#include <utility>
template <typename T1, typename... T, size_t... Indices>
std::tuple<T...> unshift_tuple_with_indices(
const std::tuple<T1, T...>& tuple, std::index_sequence<Indices...>)
{
return std::make_tuple(std::get<Indices + 1>(tuple)...);
}
template <typename T1, typename... T> std::tuple<T...>
unshift_tuple(const std::tuple<T1, T...>& tuple)
{
return unshift_tuple_with_indices(tuple,
std::make_index_sequence<sizeof...(T)>());
}
答案 0 :(得分:2)
在C ++ 14中,有一个名为std::integer_sequence
的类模板,其作用与您对sequential_integer_list
所做的相似。您可以在here中找到参考。
根据您的代码,可以减少并依赖纯元编程。
template <typename First, typename ... Elements>
struct unshift_tuple_impl
{
using type = std::tuple<Elements...>;
};
template <typename First, typename ... Elements>
std::tuple<Elements...>
unshift_tuple(const std::tuple<First, Elements...>& tuple)
{
return typename unshift_tuple_impl<First, Elements...>::type{};
}
答案 1 :(得分:1)
在C ++ 17中,您可以这样做
template <typename T1, typename... Ts>
std::tuple<Ts...> unshift_tuple(const std::tuple<T1, Ts...>& tuple)
{
return std::apply([](auto&&, const auto&... args) {return std::tie(args...);}, tuple);
}
std::apply
可能在C ++ 14中实现。
否则,在C ++ 14中,std::index_sequence
避免编写您自己的版本,从而将您的代码简化为:
namespace details
{
template <typename Tuple, size_t... Indices>
auto unshift_tuple_with_indices(
const Tuple& tuple,
std::index_sequence<Indices...> index_type)
{
return std::make_tuple(std::get<Indices + 1>(tuple)...);
}
}
template <typename T, typename... Ts>
std::tuple<Ts...> unshift_tuple(const std::tuple<T, Ts...>& tuple)
{
return details::unshift_tuple_with_indices(tuple, std::index_sequence_for<Ts...>());
}