2013-07-25 1 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 ...>에서 시작하는 하위 튜플 만들기

저는 가변성 템플릿에 상당히 익숙합니다. 첫 번째 단계로 나는 을 작성하여 std::tuple 원래 유형의 다른 유형을 저장하고 (std::tuple<decltype(old_tuple)> new_tuple에서와 같이) 동일한 종류의 새 튜플을 생성하려고했습니다. 내가하고 싶은 무엇

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님께는 type_list에 저장된 몇 가지 항목에 어떻게 액세스 할 수 있습니까? 그들 중 일부를 버리는 방법은?

감사합니다. 그것을 할 수

+0

가능한 예 http://stackoverflow.com/q/17508129/1362568 –

+0

당신의 예제에서'[0, sizeof ... (some_types) - 2]', 즉'[0, 1]'을 원하셨습니까? ? – Walter

+0

예, 수정되었습니다. 고맙습니다. –

답변

4

이런 종류의 조작은 인덱스 시퀀스 기법을 사용하면 매우 쉽습니다. 튜플보다 인덱스가 두 개인 인덱스 시퀀스를 생성하고 해당 시퀀스를 사용하여 원본에서 필드를 선택하십시오. C++ 14 형 공제를 std::make_index_sequence를 사용하여 반환 :

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>()); 
} 

(11) C++에서 :

#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

다음은 문제를 직접 해결하는 방법입니다.

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를 사용

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)...); 
} 

당신은 다음과 같이 사용할 수 있습니다.

완전히 다른 접근법은 유형과 tuple<...>을 취하고 그 유형을 끝에 추가하는 append_type을 작성하는 것입니다. 그런 다음 type_list에 추가 : 당신 template을 들고 임의의 파라미터 팩으로 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; 
}; 

합니다. 하지만 그건 당신의 문제에 꼭 필요한 것은 아닙니다.

+1

2 분 Beatcha! – Casey

+0

@ 케이시 광산 길이의 절반입니다! ...C++ 14 호환'integer_sequence' 사본을 포함한다면 ;) 오, 그리고 나는'make_seq'에서 기하 급수적으로 더 많은 재귀를 가지고 있습니다, 좋습니다. – Yakk

+0

FWIW, 로그 N 인덱스는 간단한 SO 미리보기에 너무 많은 번거 로움이 있으므로 명확하고 간결한 버전의 경우 Yakk에 +1하십시오. : P – Xeo

관련 문제