2015-02-05 7 views
7

मुझे प्रत्येक तत्व के लिए मनमाने ढंग से ट्यूपल में एक टेम्पलेट या ओवरलोडेड - कॉल करने की आवश्यकता है। सटीक होने के लिए, मुझे इस फ़ंक्शन को तत्वों पर कॉल करने की आवश्यकता है क्योंकि वे tuple में निर्दिष्ट हैं।प्राकृतिक (विपरीत नहीं) क्रम में std :: tuple में तत्वों के लिए func को लागू करना

उदाहरण के लिए।

1; 2.0f; 

और नहीं 2.0f; 1;: मैं एक टपल std::tuple<int, float> t{1, 2.0f}; और एक कार्यात्मक

class Lambda{ 
public: 
    template<class T> 
    void operator()(T arg){ std::cout << arg << "; "; } 
}; 

मैं कुछ struct/समारोह Apply, जो, अगर Apply<Lambda, int, float>()(Lambda(), t) की तरह कहा जाता प्राप्त होते हैं की जरूरत है।

ध्यान दें कि अगर मैं "कच्चे" पैरामीटर पैक को फ़ंक्शन में पास कर देता हूं तो मुझे समाधान पता है और मुझे पता है कि रिवर्स ऑर्डर में टुपल्स के लिए इसे कैसे करना है। लेकिन आंशिक रूप से Apply विशेषज्ञता के निम्नलिखित प्रयास विफल रहता है:

template<class Func, size_t index, class ...Components> 
class ForwardsApplicator{ 
public: 
    void operator()(Func func, const std::tuple<Components...>& t){ 
     func(std::get<index>(t)); 
     ForwardsApplicator<Func, index + 1, Components...>()(func, t); 
    } 
}; 

template<class Func, class... Components> 
class ForwardsApplicator < Func, sizeof...(Components), Components... > { 
public: 
    void operator()(Func func, const std::tuple<Components...>& t){} 
}; 

int main{ 
    ForwardsApplicator<Lambda, 0, int, float>()(Lambda{}, std::make_tuple(1, 2.0f)); 
} 

कोड संकलित किया गया है, लेकिन केवल पहला तर्क छपा है। हालांकि, अगर मैं

template<class Func, class... Components> 
class ForwardsApplicator < Func, 2, Components... >{...} 

साथ ForwardsApplicator विशेषज्ञता की जगह इसे सही ढंग से काम करता है - लेकिन, ज़ाहिर है, केवल लंबाई 2. साथ tuples मैं इसे कैसे करते हैं के लिए - यदि संभव हो तो, सुंदर ढंग से - मनमाना लंबाई की tuples के लिए?

संपादित करें: आपके उत्तरों के लिए धन्यवाद दोस्तों! सभी तीन वास्तव में सीधे-से-पॉइंट हैं और सभी संभावित लाभ बिंदुओं से इस मुद्दे को समझाते हैं।

उत्तर

6

समस्या यह है कि size...(Components) के लिए विशेषज्ञता में नहीं किया जा सकता है: पूंछ के tuples सिर पर कार्रवाई करने के लिए एक साधारण दृष्टिकोण सिर प्रत्यावर्तन (के रूप में पूंछ प्रत्यावर्तन के खिलाफ) है अज्ञात प्रकार की सूची Components। जीसीसी इस बारे में शिकायत के साथ शिकायत करता है:

prog.cpp:16:7: error: template argument 'sizeof... (Components)' involves template parameter(s) 
class ForwardsApplicator < Func, sizeof...(Components), Components... > { 
    ^

मैं थोड़ा अलग दृष्टिकोण सुझाता हूं। फिर,

template<class ...Components> 
void operator()(Func func, const std::tuple<Components...>& t) { 
    ... 
} 

कॉल क्रम को उल्टा:: सबसे पहले, प्रकार सूची Components टेम्पलेट पैरामीटर में operator() के लिए यानी ले जाते हैं, पहले एक पुनरावर्ती कॉल, तो index-1 साथ invokation कर (यानी पिछले पर कॉल ट्यूपल तत्व)। index = sizeof...(Components) के साथ इस रिकर्सन को शुरू करें और index = 0 तक जाएं जो नोप है (इसलिए विशेषज्ञता 0 है, sizeof...(Components) से स्वतंत्र है, जिस समस्या के बारे में मैंने बात करना शुरू किया था)।

मदद करने के लिए इस फोन, टेम्पलेट तर्क कटौती के लिए एक समारोह जोड़ें:

apply(Lambda{}, std::make_tuple(1, 2.0f)); 

: कॉल साइट पर किसी भी टेम्पलेट मापदंडों के लिए

// General case (recursion) 
template<class Func, size_t index> 
class ForwardsApplicator{ 
public: 
    template<class ...Components> 
    void operator()(Func func, const std::tuple<Components...>& t){ 
     ForwardsApplicator<Func, index - 1>()(func, t); 
     func(std::get<index - 1>(t)); 
    } 
}; 

// Special case (stop recursion) 
template<class Func> 
class ForwardsApplicator<Func, 0> { 
public: 
    template<class ...Components> 
    void operator()(Func func, const std::tuple<Components...>& t){} 
}; 

// Helper function for template type deduction 
template<class Func, class ...Components> 
void apply(Func func, const std::tuple<Components...>& t) { 
    ForwardsApplicator<Func, sizeof...(Components)>()(func, t); 
} 

यह तो आह्वान करने के लिए आसान है, आवश्यकता के बिना Live demo

+0

यही वह जवाब है जिसे मैं ढूंढ रहा था: सुरुचिपूर्ण और डिजाइन के करीब बहुत करीब था। धन्यवाद! – Mischa

+1

आप उस विशेष गैर-प्रकार के टेम्पलेट तर्क के बारे में सही हैं जो अवैध है। मुझे लगता है कि ओपी वीसी 12 का उपयोग कर रहा है, जो किसी भी त्रुटि को जारी नहीं करता है लेकिन कुछ भी अच्छा नहीं करता है; समस्या को वीसी 14 सीटीपी 5 में तय किया गया है, जो एक अच्छी त्रुटि जारी करता है। यह ध्यान देने योग्य है कि क्लैंग (3.5.0 और ट्रंक 228146) बिना किसी डायग्नोस्टिक के कोड को संकलित करता है और विशेषज्ञता से मेल खाता है। यह रिपोर्ट किया जाना चाहिए। – bogdan

2

टेम्पलेट में गिनती का मतलब यह नहीं है कि आप उसी क्रम में ट्यूपल तत्वों को संसाधित करते हैं।

#include <tuple> 
#include <iostream> 

// Our entry point is the tuple size 
template<typename Tuple, std::size_t i = std::tuple_size<Tuple>::value> 
struct tuple_applicator { 
    template<typename Func> static void apply(Tuple &t, Func &&f) { 
    // but we recurse before we process the element associated with that 
    // number, reversing the order so that the front elements are processed 
    // first. 
    tuple_applicator<Tuple, i - 1>::apply(t, std::forward<Func>(f)); 
    std::forward<Func>(f)(std::get<i - 1>(t)); 
    } 
}; 

// The recursion stops here. 
template<typename Tuple> 
struct tuple_applicator<Tuple, 0> { 
    template<typename Func> static void apply(Tuple &, Func &&) { } 
}; 

// and this is syntactical sugar 
template<typename Tuple, typename Func> 
void tuple_apply(Tuple &t, Func &&f) { 
    tuple_applicator<Tuple>::apply(t, std::forward<Func>(f)); 
} 

int main() { 
    std::tuple<int, double> t { 1, 2.3 }; 

    // The generic lambda requires C++14, the rest 
    // works with C++11 as well. Put your Lambda here instead. 
    tuple_apply(t, [](auto x) { std::cout << x * 2 << '\n'; }); 
} 

उत्पादन

2 
4.6 
9

यह integer_sequence चाल के लिए एक पाठ्यपुस्तक मामला है।

template<class Func, class Tuple, size_t...Is> 
void for_each_in_tuple(Func f, Tuple&& tuple, std::index_sequence<Is...>){ 
    using expander = int[]; 
    (void)expander { 0, ((void)f(std::get<Is>(std::forward<Tuple>(tuple))), 0)... }; 
} 

template<class Func, class Tuple> 
void for_each_in_tuple(Func f, Tuple&& tuple){ 
    for_each_in_tuple(f, std::forward<Tuple>(tuple), 
       std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>()); 
} 

Demo

std::index_sequence और दोस्त सी ++ 14 हैं, लेकिन यह एक शुद्ध लाइब्रेरी एक्सटेंशन है और आसानी से सी ++ 11 में कार्यान्वित किया जा सकता है। आप आसानी से एसओ पर आधा दर्जन कार्यान्वयन पा सकते हैं।

संबंधित मुद्दे