वैरेडिक टेम्प्लेट: समूहों में तर्क प्रकट करते हैं


16

मेरे पास एक फ़ंक्शन है जो दो तर्क देता है:

template <typename T1, typename T2>
void foo(T1 arg1, T2 arg2)
{ std::cout << arg1 << " + " << arg2 << '\n'; }

और एक वैरागी वह है जो जोड़े में अपने तर्कों को आगे बढ़ाए:

template <typename... Args>
void bar(Args&&... args) {
    static_assert(sizeof...(Args) % 2 == 0);

    ( foo( std::forward<Args>(args), std::forward<Args>(args) ), ... );
    // ^ Sends each argument twice, not in pairs
}

मैं bar(1,2,3,4)कॉल foo(1,2)और करना चाहूंगाfoo(3,4)

क्या ऐसा करने के लिए कोई रास्ता है ?


4

जवाबों:


13

आप इसे अधिभार के साथ पूरा कर सकते हैं।

template <typename T1, typename T2>
void bar(T1&& arg1, T2&& arg2) {
    foo( std::forward<T1>(arg1), std::forward<T2>(arg2) ); // (until) sends (the last) two arguments to foo
}

template <typename T1, typename T2, typename... Args>
void bar(T1&& arg1, T2&& arg2, Args&&... args) {
    foo( std::forward<T1>(arg1), std::forward<T2>(arg2) ); // sends the 1st two arguments to foo
    bar( std::forward<Args>(args)... );                    // call bar with remaining elements recursively
}

लाइव


ध्यान दें कि bar0 या विषम तर्कों के साथ कॉल करते समय ऊपर दिए गए न्यूनतम स्निपेट के साथ आपको कोई मिलान फ़ंक्शन त्रुटि नहीं मिलेगी । यदि आप चाहते हैं कि आपके साथ और अधिक स्पष्ट संकलन संदेश static_assertइस स्निपेट से शुरू हो सके ।


5

सरल पुनरावर्तन का उपयोग if constexpr:

// print as many pairs as we can
template<class T, class U, class... Args>
void foo(T t, U u, Args&&... args)
{
    std::cout << t << " + " << u << "\n";
    if constexpr(sizeof...(Args) > 0 && sizeof...(Args) % 2 == 0)
        foo(std::forward<Args>(args)...);
}

template<class... Args>
void bar(Args&&... args)
{
    static_assert(sizeof...(Args) % 2 == 0);
    foo(std::forward<Args>(args)...);
}

इसे ऐसे कॉल करें:

bar(1, 2, 3, 4);

डेमो

मैं कहूंगा कि गीतयानाओ का उत्तर सुंदर विहित पूर्व-सी ++ 17 है। बाद में, if constexprहमें ओवरलोडिंग ट्रिक्स का उपयोग करने के बजाय अपने कार्यों के निकायों में तर्क को स्थानांतरित करने की अनुमति दी है।


1
गीतयानाओ के संस्करण का विस्तार करना बहुत आसान है, जैसे कि यह फ़ंक्शन को तर्क के रूप में लागू करने में भी लेता है। मेरी राय में यह बहुत अच्छा है, क्योंकि यह हमें तर्क को हर बार लिखने के बिना कई बार इस पैटर्न को लागू करने की अनुमति देता है। क्या आपके उत्तर का एक संस्करण है जो समान अनुमति देता है?
n314159

1
@ n314159: कुछ इस तरह ?
एंडीग

1
बिल्कुल सही! धन्यवाद। व्यक्तिगत रूप से मैं इसे पसंद करता हूं, चूंकि (इसके अलावा जो मैंने पहले ही कहा था) यह उस फ़ंक्शन से लागू-तर्क को अलग करता है जिस पर इसे लागू किया जाता है।
n314159

2

C ++ 17 सामान्य- nरूपांतरणकर्ता के लिए सामान्यीकरण :

namespace impl
{
    template<std::size_t k, class Fn, class Tuple, std::size_t... js>
    void unfold_nk(Fn fn, Tuple&& tuple, std::index_sequence<js...>) {
        fn(std::get<k + js>(std::forward<Tuple>(tuple))...);
    }

    template<std::size_t n, class Fn, class Tuple, std::size_t... is>
    void unfold_n(Fn fn, Tuple&& tuple, std::index_sequence<is...>) {
        (unfold_nk<n * is>(fn, std::forward<Tuple>(tuple), 
            std::make_index_sequence<n>{}), ...);
    }
}

template<std::size_t n, class Fn, typename... Args>
void unfold(Fn fn, Args&&... args) {
    static_assert(sizeof...(Args) % n == 0);
    impl::unfold_n<n>(fn, std::forward_as_tuple(std::forward<Args>(args)...), 
        std::make_index_sequence<sizeof...(Args) / n>{});
}

int main() {
    auto fn = [](auto... args) { 
        (std::cout << ... << args) << ' ';
    };

    unfold<2>(fn, 1, 2, 3, 4, 5, 6);   // Output: 12 34 56
    unfold<3>(fn, 1, 2, 3, 4, 5, 6);   // Output: 123 456
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.