다양한 템플릿 : 그룹에서 인수 펼치기


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
같은 인수를 두 번 전달하는 것은 위험합니다
AndyG

답변:


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);

데모

나는 songyanyao의 대답 이 표준 C ++ 17이라는 정식 이라고 말하고 싶습니다 . 그 후, if constexpr오버로드 트릭을 사용하는 대신 로직을 함수 본문으로 옮길 수있었습니다.


1
songyanyao의 버전은 확장하기가 쉽기 때문에 인수로 적용하는 기능을 수행합니다. 내 생각에 이것은 매번 논리를 쓰지 않고도이 패턴을 여러 번 적용 할 수 있기 때문에 꽤 좋습니다. 동일한 답변을 제공하는 답변이 있습니까?
n314159

1
@ n314159 : 이것 같은 ?
AndyG

1
바로 그거죠! 감사합니다. 개인적으로 나는 (내가 이미 말한 것에 추가하여) 적용 논리와 적용되는 기능을 분리하기 때문에 이것을 선호합니다.
n314159

2

n-ary functors에 대한 C ++ 17 일반화 :

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.