ভারিয়াদিক টেমপ্লেট: দলগুলিতে যুক্তি প্রকাশ করা


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)

এটা করার কোন উপায় আছে?


উত্তর:


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

সি ++ 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
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.