2017-01-24 1 views
3

나는 가변 인자 템플릿 함수 foo() 있습니다. some metaprogramming을 사용하여 시행 할 수 있습니다. 결과 인수 목록을 두 번씩 가져 와서 std::pair<size_t, size_t> 컨테이너에 넣어야합니다. 개념적으로는 다음과 같습니다.어떻게 C++ 매개 변수 팩을 std :: pair 객체의 시퀀스에 매핑 할 수 있습니까?</p> <pre><code>template <typename... Args> void foo(Args &&... args); </code></pre> <p>이 기능은 <code>size_t</code>의 모든 인수를 호출하기위한 것입니다 :

std::vector<std::pair<size_t, size_t> > = { 
    std::make_pair(args[0], args[1]), 
    std::make_pair(args[2], args[3]), ... 
}; 

직접적인 방법이 있습니까? 팩 확장으로 인수를 평면 컨테이너에 넣을 수는 있지만 두 개씩 두 개씩을 std::pair 개의 객체로 동시에 그룹화하는 방법이 있습니까?

+0

"* 이것을 할 수있는 간단한 방법이 있습니까? *"No. –

+1

두 개의 인수를 사용하는 재귀 적 삽입기를 만들 수 있고 두 개의 정지 사례 특수화를 사용하여 벡터로 쌍을 push_back 할 수 있습니다. – luk32

+0

추가 std :: index_sequence 매개 변수가있는 내부 도우미 함수로 전달할 가능성이 있습니까? –

답변

6

팩에 대한 인덱싱은 실제로 할 수 없지만 아직 튜플에 대한 인덱싱은 아닙니다. 먼저 튜플에 모든 것을 집어 넣은 다음 이동하면서 모든 것을 꺼내십시오. 모든 것이 size_t이기 때문에, 우리는 그냥 복사 할 수 있습니다 :

template <typename ...Args> 
void foo(Args &&... args) 
{ 
    foo_impl(std::make_index_sequence<sizeof...(Args)/2>(), 
      std::forward<Args>(args)...); 
} 

이제 우리는 인덱스 인수 팩 지수에서 작동 할 수 있습니다 :

template <size_t... Is, class Tuple> 
std::vector<std::pair<size_t, size_t>> 
foo_impl(std::index_sequence<Is...>, Tuple tuple) { 
    return std::vector<std::pair<size_t, size_t> >{ 
     std::make_pair(std::get<2*Is>(tuple), std::get<2*Is+1>(tuple))... 
    }; 
} 

template <typename... Args> 
void foo(Args... args) 
{ 
    auto vs = foo_impl(std::make_index_sequence<sizeof...(Args)/2>{}, 
     std::make_tuple(args...)); 

    // ... 
} 
+0

아마'std :: forward_as_tuple'입니까? –

+0

@KerrekSB 모두'size_t'입니다. 컴파일러가 어쨌든'튜플 (tuple) '을 제거 할 것이라는 확신이들 것입니다. – Barry

2

당신은 내부 도우미 기능으로 로직을 리팩토링 할 수있다 가정하자 :

template <std::size_t ...I, typename ...Args> 
void foo_impl(std::index_sequence<I...>, Args &&... args) 
{ 
    std::vector<std::pair<std::size_t, std::size_t>> v = 
     { GetPair(std::integral_constant<std::size_t, I>(), args...)... }; 
} 
그것은 한 쌍 추출기 구현하기 위해 남아

:

+0

우수. 배리의 대답은 조금 더 간결했기 때문에 받아 들였습니다. 그러나 이것은 좋은 해결책처럼 보입니다. –

+0

@JasonR : 예,'std :: get'은 원시 팩을위한 제 GetPair의 튜플에 효과적으로 적용됩니다. 튜플은 이러한 종류의 일반 코드에 매우 강력합니다. –

2

range-v3, 당신이 할 수

template <typename... Args> 
void foo(Args&&... args) 
{ 
    std::initializer_list<std::size_t> nbs = {static_cast<std::size_t>(args)...}; 
    const auto pair_view = 
     ranges::view::zip(nbs | ranges::view::stride(2), 
          nbs | ranges::view::drop(1) | ranges::view::stride(2)); 

    // And possibly 
    std::vector<std::pair<std::size_t, std::size_t>> pairs = pair_view; 
    // ... 
} 

Demo

+0

범위가 아름답습니다. –

+0

마지막 줄은 다음과 같이 굵게 표시 될 수 있습니다 : auto pairs = pair_view | 변환 ({반환 std :: make_pair (...);}) | ranges :: to_vector; –

+0

나는 이것을 많이 좋아한다. 원래이 라인을 따라 생각하고 있었지만 범위가 표준에 도달 할 때까지 기다려야 할 것입니다! –

1

사람 (기침 @Barry 기침는) 팩에 인덱싱이 불가능하다고 말했다.

이것은 C++입니다. Impossible은 아직 작성하지 않았 음을 의미합니다.

template<std::size_t I> struct index_t:std::integral_constant<std::size_t, I> { 
    using std::integral_constant<std::size_t, I>::integral_constant; 
    template<std::size_t J> 
    constexpr index_t<I+J> operator+(index_t<J>) const { return {}; } 
    template<std::size_t J> 
    constexpr index_t<I-J> operator-(index_t<J>) const { return {}; } 
    template<std::size_t J> 
    constexpr index_t<I*J> operator*(index_t<J>) const { return {}; } 
    template<std::size_t J> 
    constexpr index_t<I/J> operator/(index_t<J>) const { return {}; } 
}; 
template<std::size_t I> 
constexpr index_t<I> index{}; 

template<std::size_t B> 
constexpr index_t<1> exponent(index_t<B>, index_t<0>) { return {}; } 

template<std::size_t B, std::size_t E> 
constexpr auto exponent(index_t<B>, index_t<E>) { 
    return index<B> * exponent(index<B>, index<E-1>); 
} 
template<std::size_t N> 
constexpr index_t<0> from_base(index_t<N>) { return {}; } 
template<std::size_t N, std::size_t c> 
constexpr index_t<c-'0'> from_base(index_t<N>, index_t<c>) { return {}; } 
template<std::size_t N, std::size_t c0, std::size_t...cs> 
constexpr auto from_base(index_t<N>, index_t<c0>, index_t<cs>...) { 
    return 
    from_base(index<N>, index<c0>) * exponent(index<N>, index<sizeof...(cs)>) 
    + from_base(index<N>, index<cs>...) 
    ; 
} 

template<char...cs> 
constexpr auto operator""_idx(){ 
    return from_base(index<10>, index<cs>...); 
} 

auto nth = [](auto index_in){ 
    return [](auto&&...elems)->decltype(auto){ 
    using std::get; 
    constexpr auto I= index<decltype(index_in){}>; 
    return get<I>(std::forward_as_tuple(decltype(elems)(elems)...)); 
    }; 
}; 

이제 우리는 얻을 :

using pair_vec = std::vector<std::pair<std::size_t, std::size_t>>; 
template <typename... Args> 
pair_vec foo(Args &&... args) { 
    return 
    index_over< sizeof...(args)/2 >() 
    ([&](auto...Is)->pair_vec{ 
     return { 
     { 
      nth(Is*2_idx)(decltype(args)(args)...), 
      nth(Is*2_idx+1_idx)(decltype(args)(args)...) 
     }... 
     }; 
    }); 
} 

경우 시정 인덱스를 컴파일하여 우리의 매개 변수 팩에 우리는 "직접"인덱스입니다.

live example.

+0

매우 인상적입니다. 저는 현대 C++ 곡선보다 몇 년 뒤입니다. 그래서 저는 처음부터 이와 같은 해결책을 꿈꾸는 것에서 먼 길을 가고 있습니다. 좋은 데모. –

관련 문제