2013-07-25 45 views
4

創建子元組讓我們假設給出了std::tuple<some_types...>。我想創建一個新的std::tuple,其類型是在[0, sizeof...(some_types) - 2]索引的類型。例如,假設起始元組是std::tuple<int, double, bool>。我想獲得一個定義爲std::tuple<int, double>的子元組。從std :: tuple <some_types ...>

我對variadic模板很陌生。作爲第一步我試圖在電荷儲存不同類型的原std::tuple的與創建的相同種類的新的元組(如在std::tuple<decltype(old_tuple)> new_tuple)的目標的寫struct

template<typename... types> 
struct type_list; 

template<typename T, typename... types> 
struct type_list<T, types...> : public type_list<types...> { 
    typedef T type; 
}; 


template<typename T> 
struct type_list<T> { 
    typedef T type; 
}; 

我想要做的是一樣的東西:

std::tuple<type_list<bool, double, int>::type...> new_tuple // this won't work 

,下一步將在參數包丟棄最後一個元素。我如何訪問type_list中存儲的幾個type?以及如何丟棄其中的一些?

謝謝。

+0

的http://stackoverflow.com/q/17508129/1362568 –

+0

可能的複製您是不是要找'[0,...的sizeof(some_types) - 2]','即[0,1]'在你的榜樣? – Walter

+0

是的,更正了。謝謝。 –

回答

4

這種操縱是與索引序列技術相當簡單:生成兩種比你少的元組索引的索引序列,並使用該序列來選擇從原來的領域。使用std::make_index_sequence和返回類型扣除從C++ 14:

template <typename... T, std::size_t... I> 
auto subtuple_(const std::tuple<T...>& t, std::index_sequence<I...>) { 
    return std::make_tuple(std::get<I>(t)...); 
} 

template <int Trim, typename... T> 
auto subtuple(const std::tuple<T...>& t) { 
    return subtuple_(t, std::make_index_sequence<sizeof...(T) - Trim>()); 
} 

在C++ 11:

#include <cstddef>  // for std::size_t 

template<typename T, T... I> 
struct integer_sequence { 
    using value_type = T; 

    static constexpr std::size_t size() noexcept { 
    return sizeof...(I); 
    } 
}; 

namespace integer_sequence_detail { 
template <typename, typename> struct concat; 

template <typename T, T... A, T... B> 
struct concat<integer_sequence<T, A...>, integer_sequence<T, B...>> { 
    typedef integer_sequence<T, A..., B...> type; 
}; 

template <typename T, int First, int Count> 
struct build_helper { 
    using type = typename concat< 
    typename build_helper<T, First,   Count/2>::type, 
    typename build_helper<T, First + Count/2, Count - Count/2>::type 
    >::type; 
}; 

template <typename T, int First> 
struct build_helper<T, First, 1> { 
    using type = integer_sequence<T, T(First)>; 
}; 

template <typename T, int First> 
struct build_helper<T, First, 0> { 
    using type = integer_sequence<T>; 
}; 

template <typename T, T N> 
using builder = typename build_helper<T, 0, N>::type; 
} // namespace integer_sequence_detail 

template <typename T, T N> 
using make_integer_sequence = integer_sequence_detail::builder<T, N>; 

template <std::size_t... I> 
using index_sequence = integer_sequence<std::size_t, I...>; 

template<size_t N> 
using make_index_sequence = make_integer_sequence<size_t, N>; 

#include <tuple> 

template <typename... T, std::size_t... I> 
auto subtuple_(const std::tuple<T...>& t, index_sequence<I...>) 
    -> decltype(std::make_tuple(std::get<I>(t)...)) 
{ 
    return std::make_tuple(std::get<I>(t)...); 
} 

template <int Trim, typename... T> 
auto subtuple(const std::tuple<T...>& t) 
    -> decltype(subtuple_(t, make_index_sequence<sizeof...(T) - Trim>())) 
{ 
    return subtuple_(t, make_index_sequence<sizeof...(T) - Trim>()); 
} 

Live at Coliru

1

一種方式做到這一點是遞歸地傳遞兩個元組到一個輔助結構,是以「源」元組的第一個元素,並將其添加到另一個的端部:

#include <iostream> 
#include <tuple> 
#include <type_traits> 

namespace detail { 

    template<typename...> 
    struct truncate; 

    // this specialization does the majority of the work 

    template<typename... Head, typename T, typename... Tail> 
    struct truncate< std::tuple<Head...>, std::tuple<T, Tail...> > { 
     typedef typename 
     truncate< std::tuple<Head..., T>, std::tuple<Tail...> >::type type; 
    }; 

    // this one stops the recursion when there's only 
    // one element left in the source tuple 

    template<typename... Head, typename T> 
    struct truncate< std::tuple<Head...>, std::tuple<T> > { 
     typedef std::tuple<Head...> type; 
    }; 
} 

template<typename...> 
struct tuple_truncate; 

template<typename... Args> 
struct tuple_truncate<std::tuple<Args...>> { 

    // initiate the recursion - we start with an empty tuple, 
    // with the source tuple on the right 

    typedef typename detail::truncate< std::tuple<>, std::tuple<Args...> >::type type; 
}; 

int main() 
{ 
    typedef typename tuple_truncate< std::tuple<bool, double, int> >::type X; 

    // test 
    std::cout << std::is_same<X, std::tuple<bool, double>>::value; // 1, yay 
} 

Live example

5

以下是直接解決問題的方法。

template<unsigned...s> struct seq { typedef seq<s...> type; }; 
template<unsigned max, unsigned... s> struct make_seq:make_seq<max-1, max-1, s...> {}; 
template<unsigned...s> struct make_seq<0, s...>:seq<s...> {}; 

template<unsigned... s, typename Tuple> 
auto extract_tuple(seq<s...>, Tuple& tup) { 
    return std::make_tuple(std::get<s>(tup)...); 
} 

如下您可以使用此:

std::tuple< int, double, bool > my_tup; 
auto short_tup = extract_tuple(make_seq<2>(), my_tup); 
auto skip_2nd = extract_tuple(seq<0,2>(), my_tup); 

,並使用decltype如果您需要的結果類型。

另一種方法是編寫append_type,其中採用一個類型和一個tuple<...>,並將該類型添加到最後。然後添加到type_list

template<template<typename...>class target> 
struct gather { 
    typedef typename type_list<types...>::template gather<target>::type parent_result; 
    typedef typename append< parent_result, T >::type type; 
}; 

,讓你的方式來積累類型的type_list到任意參數袋保持template。但這不是你的問題所必需的。

+1

由兩分鐘的Beatcha! – Casey

+0

@Casey礦是長度的一半! ...如果包括你的一個C++ 14兼容'integer_sequence'的副本。 ;)喔,我在我的'make_seq'成倍地遞歸,這是很好的,對不對? – Yakk

+0

FWIW,我認爲登錄N個索引太多的麻煩簡單SO片段,所以+1 Yakk的清晰,簡潔的版本。 :P – Xeo

相關問題