Değişken şablonları: gruplar halinde bağımsız değişkenler açın


16

İki argüman alan bir işlevi var:

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

Ve argümanlarını çiftler halinde iletmesi gereken varyatik bir açıklama:

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
}

Ben isteyeyim bar(1,2,3,4)aramak foo(1,2)vefoo(3,4)

Bunu yapmanın bir yolu var mı?


4
Aynı
tartışmaları

Yanıtlar:


13

Aşırı yüklerle başarabilirsiniz.

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
}

CANLI


bar0 veya tek değişkenlerle çağrı yaparken yukarıdaki minimum snippet ile eşleşen işlev hatası almayacağınızı unutmayın. Daha net bir derleme mesajı static_assertistiyorsanız bu snippet'ten başlayabilirsiniz .


5

Kullanarak basit özyineleme 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)...);
}

Şöyle deyin:

bar(1, 2, 3, 4);

gösteri

Songyanyao'nun cevabının oldukça kanonik C ++ 17 öncesi olduğunu söyleyebilirim . Daha sonra, if constexprmantığı aşırı yükleme hileleri kullanmak yerine fonksiyonlarımızın bedenlerine taşımamıza izin verdi.


1
songyanyao'nun versiyonunun genişletilmesi oldukça kolaydır, öyle ki argüman olarak uyguladığı işlevi de alır. Bence bu oldukça hoş, çünkü bu modeli her seferinde mantık yazmak zorunda kalmadan birçok kez uygulamamıza izin veriyor. Cevabınızın buna izin veren bir sürümü var mı?
n314159

1
@ n314159: Böyle bir şey bu ?
AndyG

1
Kesinlikle! Teşekkür ederim. Şahsen bunu tercih ederim, çünkü (zaten söylediğim şeye ek olarak), uygulama mantığını uygulandığı işlevden ayırır.
n314159

2

n-Ary functors için C ++ 17 genellemesi :

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
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.