我正在尝试返回std::tuple
中最后一个元素以外的所有内容,如果元组中只有两个元素,请返回第一个。由于std::tuple
具有许多编译时功能,因此双返回类型应该是可行的。这是我到目前为止的内容:
// Behavior
// init(std::make_tuple(1,2)) = 1
// init(std::make_tuple(1,2,3)) = (1,2)
// First case
template<class T1, class T2>
inline static T1 init(Tuple<T1, T2> t) {
return std::get<0>(t);
}
// Second case
template<class ...Args, class S = std::make_index_sequence<sizeof...(Args) - 1>>
inline static decltype(auto) init(Tuple<Args...> t) {
return std::apply([](const auto &item...) {
return std::tuple_cat(std::make_tuple(std::get<S>) ... std::tuple<>);
}, t);
}
如果我能以c ++ 17友好的方式做到这一点,那就太好了。上面的实现出现以下错误:
./ tuple.cpp:36:55:错误:数据包扩展不包含任何未扩展的参数包
返回std :: tuple_cat(std :: make_tuple(std :: get)... std :: tuple <>);~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^^
产生1个错误。
答案 0 :(得分:2)
与您的问题无关,但模板暗含inline
,并且您不希望使用static
。我实际上认为static
违反了ODR。为什么使用它们?您也可以使函数constexpr
。进一步的改进是使用(转发)引用和std::forward_as_tuple
。这是一个基本的实现:
template <class... Args, std::size_t... Is>
constexpr auto init_helper(std::tuple<Args...> tp, std::index_sequence<Is...>)
{
return std::tuple{std::get<Is>(tp)...};
}
template <class... Args>
constexpr auto init(std::tuple<Args...> tp)
{
return init_helper(tp, std::make_index_sequence<sizeof...(Args) - 1>{});
}
auto test()
{
static_assert(init(std::tuple{1}) == std::tuple{});
static_assert(init(std::tuple{1, 2}) == std::tuple{1});
static_assert(init(std::tuple{1, 2, 3}) == std::tuple{1, 2});
}
您在评论中说,您想查看init(std::tuple{1,2})
是否有可能直接返回值而不是一个值的元组。注意,我不建议这样做,因为这会使函数的行为不一致,是的,这是可能的。而C++17
使这一点变得非常干净:
template <class... Args>
constexpr auto init(std::tuple<Args...> tp)
{
if constexpr (sizeof...(Args) == 2)
return std::get<0>(tp);
else
return init_helper(tp, std::make_index_sequence<sizeof...(Args) - 1>{});
}
auto test()
{
static_assert(init(std::tuple{1}) == std::tuple{});
static_assert(init(std::tuple{1, 2}) == 1);
static_assert(init(std::tuple{1, 2, 3}) == std::tuple{1, 2});
}
答案 1 :(得分:1)
该想法将是实现一个辅助函数,该函数将具有要复制的源元组项的索引列表:
#include <tuple>
#include <utility>
#include <cstddef>
template<typename x_Tuple, ::std::size_t... x_index> auto
make_tuple_helper(x_Tuple const & other, ::std::index_sequence<x_index...>)
{
return ::std::make_tuple(::std::get<x_index>(other)...);
}
template<typename... x_Field> inline auto
cut_last_item(::std::tuple<x_Field...> const & other)
{
return make_tuple_helper(other, ::std::make_index_sequence<sizeof...(x_Field) - ::std::size_t{1}>{});
}
template<> inline auto
cut_last_item(::std::tuple<> const & other)
{
return other;
}
int main()
{
::std::tuple<int, short, float, double> t4{};
::std::tuple<int, short, float> t3{cut_last_item(t4)};
::std::tuple<int, short> t2{cut_last_item(t3)};
::std::tuple<int> t1{cut_last_item(t2)};
::std::tuple<> t0{cut_last_item(t1)};
::std::tuple<> t00{cut_last_item(t0)};
}