2011-12-20 19 views
20

मिल रहा अज्ञात आकार का एक टपल (यह टेम्पलेट विधि का parametr) हैएसटीडी का हिस्सा :: टपल

यह इसका हिस्सा (मैं इसे के पहले तत्व फेंक की जरूरत है)

पाने के लिए रास्ता नहीं है उदाहरण के लिए, मेरे पास tuple<int,int,int>(7,12,42) है। मुझे tuple<int,int>(12,42) यहां

+1

आप सच variadic टेम्पलेट समर्थन है ('टेम्पलेट <वर्ग ... args>')? साथ ही, क्या आप मानों की प्रतिलिपि बनाना चाहते हैं या आप उनमें से * दृश्य * चाहते हैं, जैसा मूल में संदर्भ हैं? – Xeo

+0

@Xeo: मुझे संदर्भ बेहतर चाहिए, लेकिन यह वास्तव में कोई फर्क नहीं पड़ता। – RiaD

+0

@Xeo: अब मैं विविध टेम्पलेट्स का उपयोग नहीं करता हूं। लेकिन मैं g ++ 4.6 पर C++ 0x का उपयोग करता हूं और मुझे लगता है कि वे समर्थित हैं। – RiaD

उत्तर

15
साथ

एक संकलन-समय पूर्णांक सूची की सहायता:

#include <cstdlib> 

template <size_t... n> 
struct ct_integers_list { 
    template <size_t m> 
    struct push_back 
    { 
     typedef ct_integers_list<n..., m> type; 
    }; 
}; 

template <size_t max> 
struct ct_iota_1 
{ 
    typedef typename ct_iota_1<max-1>::type::template push_back<max>::type type; 
}; 

template <> 
struct ct_iota_1<0> 
{ 
    typedef ct_integers_list<> type; 
}; 

हम पैरामीटर पैक विस्तार से बस पूंछ का निर्माण कर सकते हैं:

#include <tuple> 

template <size_t... indices, typename Tuple> 
auto tuple_subset(const Tuple& tpl, ct_integers_list<indices...>) 
    -> decltype(std::make_tuple(std::get<indices>(tpl)...)) 
{ 
    return std::make_tuple(std::get<indices>(tpl)...); 
    // this means: 
    // make_tuple(get<indices[0]>(tpl), get<indices[1]>(tpl), ...) 
} 

template <typename Head, typename... Tail> 
std::tuple<Tail...> tuple_tail(const std::tuple<Head, Tail...>& tpl) 
{ 
    return tuple_subset(tpl, typename ct_iota_1<sizeof...(Tail)>::type()); 
    // this means: 
    // tuple_subset<1, 2, 3, ..., sizeof...(Tail)-1>(tpl, ..) 
} 

उपयोग:

#include <cstdio> 

int main() 
{ 
    auto a = std::make_tuple(1, "hello", 7.9); 
    auto b = tuple_tail(a); 

    const char* s = nullptr; 
    double d = 0.0; 
    std::tie(s, d) = b; 
    printf("%s %g\n", s, d); 
    // prints: hello 7.9 

    return 0; 
} 

(ideone पर: http://ideone.com/Tzv7v; कोड जी ++ 4.5 से 4.7 और क्लैंग ++ 3.0 में काम करता है)

+0

मैं "कारखाने से आने वाली चीज़" की खोज कर रहा था। और मुझे लगता है कि पूछताछ भी ऐसी चीज मांग रहा था। – sergiol

+1

ध्यान दें कि आप C++ 14 में 'ct_integers_list' के बजाय' std :: index_sequence' का उपयोग कर सकते हैं। – LogicStuff

9

एक आसान तरीका हो सकता है, लेकिन यह एक शुरुआत है। "पूंछ" फ़ंक्शन टेम्पलेट पहले को छोड़कर मूल के सभी मानों के साथ एक प्रतिलिपि टुपल देता है। यह सी ++ 0x-मोड में जीसीसी 4.6.2 के साथ संकलित करता है।

template<size_t I> 
struct assign { 
    template<class ResultTuple, class SrcTuple> 
    static void x(ResultTuple& t, const SrcTuple& tup) { 
    std::get<I - 1>(t) = std::get<I>(tup); 
    assign<I - 1>::x(t, tup); 
    } 
}; 

template<> 
struct assign<1> { 
    template<class ResultTuple, class SrcTuple> 
    static void x(ResultTuple& t, const SrcTuple& tup) { 
    std::get<0>(t) = std::get<1>(tup); 
    } 
}; 


template<class Tup> struct tail_helper; 

template<class Head, class... Tail> 
struct tail_helper<std::tuple<Head, Tail...>> { 
    typedef typename std::tuple<Tail...> type; 
    static type tail(const std::tuple<Head, Tail...>& tup) { 
    type t; 
    assign<std::tuple_size<type>::value>::x(t, tup); 
    return t; 
    } 
}; 

template<class Tup> 
typename tail_helper<Tup>::type tail(const Tup& tup) { 
    return tail_helper<Tup>::tail(tup); 
} 
+0

मुझे यह इंगित करना है कि 'टेम्पलेट struct tuple_trunc {};' कभी भी तत्काल नहीं है इसे लिखा जा सकता है: 'template संरचना tuple_trunc; 'अगर कोई गलती से ऐसा करता है तो संकलक त्रुटि का कारण बन जाएगा। –

+0

@veso - मुझे इस उत्तर में कोई भी "tuple_trunc" नहीं दिखाई देता है। –

+0

हालांकि आपके कार्यान्वयन के लिए डिफ़ॉल्ट रचनात्मक प्रकार की आवश्यकता है। – Jarod42

6

मैं Adam's code में कुछ सुधार किए कि बंद टपल के पहले एन तर्क पट्टी होगा, साथ ही केवल पिछले एन प्रकार के साथ एक नया टपल बनाने ... यहाँ पूरा कोड (नोट है: किसी को भी मेरा उत्तर +1 करने के लिए, यह भी निर्णय लेता है तो कृपया +1 कि जब एडम जवाब क्या इस कोड पर आधारित है, और मैं किसी भी क्रेडिट उनके योगदान से दूर ले करने के लिए) इच्छा नहीं है:

//create a struct that allows us to create a new tupe-type with the first 
//N types truncated from the front 

template<size_t N, typename Tuple_Type> 
struct tuple_trunc {}; 

template<size_t N, typename Head, typename... Tail> 
struct tuple_trunc<N, std::tuple<Head, Tail...>> 
{ 
    typedef typename tuple_trunc<N-1, std::tuple<Tail...>>::type type; 
}; 

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

/*-------Begin Adam's Code----------- 

Note the code has been slightly modified ... I didn't see the need for the extra 
variadic templates in the "assign" structure. Hopefully this doesn't break something 
I didn't forsee 

*/ 

template<size_t N, size_t I> 
struct assign 
{ 
    template<class ResultTuple, class SrcTuple> 
    static void x(ResultTuple& t, const SrcTuple& tup) 
    { 
     std::get<I - N>(t) = std::get<I>(tup); 
     assign<N, I - 1>::x(t, tup); //this offsets the assignment index by N 
    } 
}; 

template<size_t N> 
struct assign<N, 1> 
{ 
    template<class ResultTuple, class SrcTuple> 
    static void x(ResultTuple& t, const SrcTuple& tup) 
    { 
     std::get<0>(t) = std::get<1>(tup); 
    } 
}; 


template<size_t TruncSize, class Tup> struct th2; 

//modifications to this class change "type" to the new truncated tuple type 
//as well as modifying the template arguments to assign 

template<size_t TruncSize, class Head, class... Tail> 
struct th2<TruncSize, std::tuple<Head, Tail...>> 
{ 
    typedef typename tuple_trunc<TruncSize, std::tuple<Head, Tail...>>::type type; 

    static type tail(const std::tuple<Head, Tail...>& tup) 
    { 
     type t; 
     assign<TruncSize, std::tuple_size<type>::value>::x(t, tup); 
     return t; 
    } 
}; 

template<size_t TruncSize, class Tup> 
typename th2<TruncSize, Tup>::type tail(const Tup& tup) 
{ 
    return th2<TruncSize, Tup>::tail(tup); 
} 

//a small example 
int main() 
{ 
    std::tuple<double, double, int, double> test(1, 2, 3, 4); 
    tuple_trunc<2, std::tuple<double, double, int, double>>::type c = tail<2>(test); 
    return 0; 
} 
+0

ऐसा लगता है कि आप वहां varidics के बारे में सही हैं, पिछले दृष्टिकोण से छोड़ दिया जाना चाहिए। –

2

कृपया उपयोग न करें!

  • यह [संभवत] अनिर्दिष्ट व्यवहार है। यह किसी भी समय काम करना बंद कर सकता है।
  • इसके अलावा, पैडिंग मुद्दों की संभावना है (यानी यह int के लिए काम कर सकता है लेकिन आपके प्रकार के लिए असफल हो सकता है!)।

चर्चा के लिए टिप्पणियां देखें। मैं सिर्फ संदर्भ के लिए यह जवाब छोड़ रहा हूँ।


भी सरल:

tuple<int,int,int> origin{7,12,42}; 
tuple<int, int> &tail1 = (tuple<int, int>&)origin; 
tuple<int> &tail2 = (tuple<int>&)origin; 
cout << "tail1: {" << get<0>(tail1) << ", " << get<1>(tail1) << "}" << endl; 
cout << "tail2: {" << get<0>(tail2) << "}" << endl; 

मुझे मिल गया:

tail1: {12, 42} 
tail2: {42} 

मैं कुछ नहीं कर रहा हूँ कि यह एक अनिर्दिष्ट व्यवहार नहीं है। मेरे लिए काम करता है: फेडोरा 20 और

❯ clang --version 
clang version 3.3 (tags/RELEASE_33/final) 
Target: x86_64-redhat-linux-gnu 
Thread model: posix 
❯ gcc --version 
gcc (GCC) 4.8.2 20131212 (Red Hat 4.8.2-7) 
Copyright (C) 2013 Free Software Foundation, Inc. 
This is free software; see the source for copying conditions. There is NO 
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 

संदर्भ: article on voidnish.wordpress.com/

+0

मुझे स्पष्टीकरण के बिना डाउनवॉट्स पसंद है ... – kgadek

+0

यह एक सुंदर जवाब है। क्या यह पोर्टेबल है? –

+0

सचमुच मुझे कोई जानकारी नहीं है। अब मेरा जवाब देखकर और इसके बारे में सोचते हुए, मुझे लगता है कि दुर्भाग्य से यह पोर्टेबल नहीं हो सकता है। – kgadek

3

एक टपल टुकड़ा आपरेशन (वह भी std::array और std::pair के लिए काम करता है) इस (सी ++ 14 आवश्यक) की तरह परिभाषित किया जा सकता:

namespace detail 
{ 
    template <std::size_t Ofst, class Tuple, std::size_t... I> 
    constexpr auto slice_impl(Tuple&& t, std::index_sequence<I...>) 
    { 
     return std::forward_as_tuple(
      std::get<I + Ofst>(std::forward<Tuple>(t))...); 
    } 
} 

template <std::size_t I1, std::size_t I2, class Cont> 
constexpr auto tuple_slice(Cont&& t) 
{ 
    static_assert(I2 >= I1, "invalid slice"); 
    static_assert(std::tuple_size<std::decay_t<Cont>>::value >= I2, 
     "slice index out of bounds"); 

    return detail::slice_impl<I1>(std::forward<Cont>(t), 
     std::make_index_sequence<I2 - I1>{}); 
} 

और एक टपल की एक मनमाना सबसेट t प्राप्त किया जा सकता इसलिए जैसे:

tuple_slice<I1, I2>(t); 

कहाँ [I1, I2) है विशेष रेंज सबसेट और वापसी मान के एक tupl है इनपुट टुपल क्रमशः एक लवल्यू या रावल्यू है या नहीं, इसके आधार पर संदर्भ या मूल्यों का ई (मेरे blog में एक संपूर्ण विस्तार पाया जा सकता है)।

4
के साथ सी ++ 17

, आप std::apply उपयोग कर सकते हैं:

template <typename Head, typename... Tail> 
std::tuple<Tail...> tuple_tail(const std::tuple<Head, Tail...>& t) 
{ 
    return apply([](auto head, auto... tail) { 
     return std::make_tuple(tail...)}; 
    }, t); 
} 
संबंधित मुद्दे