2017-12-17 37 views
2

매개 변수 팩이 목록의 마지막 매개 변수가 아닌 가변적 템플릿 함수를 사용하려고합니다. 재귀 호출은 두 가지가 있습니다. 하나는 매개 변수를 팩 앞에 놓고, 다른 하나는 매개 변수를 팩 뒤에 놓습니다.매개 변수 팩이 마지막 매개 변수가 아닌 C++에서 가변 템플릿 함수를 작성하려면 어떻게해야합니까?

  • 내 컴파일러로 나타납니다 애플 LLVM 버전 8.1.0을 (그 소리-802.0.42)
  • 아래 모든 INT 년대 나는이 작업을 얻을 수 있다면 새로운 T 템플릿 매개 변수가 될 것입니다.

블렌더의 통화 사이트를 청소할 수없는 경우에는 사용하지 않아도됩니다. 이 경우 블렌더의 여러 오버로드를 확장 할 수 있습니다. 나는 이것에 의지하지 않을 것이다. 내가 뭔가를 놓치기를 바란다.

int Blender(double t, int i) 
{ 
    return i; 
} 

template <typename ...Args> 
    int Blender(double t, int first, Args... more, int last) 
{ 
    return (1-t)*Blender(t, first, more...) + t*Blender(t, more..., last); 
} 

static void tryit() 
{ 
    Blender(.5, 23, 42, 89); //doesn't compile 
} 
+6

길고도 짧은 이야기, 그것은 불가능합니다. 팩은 디자인에 의해 "탐욕 스럽다". – StoryTeller

+0

C++에서 currying을 수행하는 방법과 매우 유사 할 수 있습니다. 비틀기는 마지막 매개 변수를 끄집어 내고 당신이 그것으로하고 싶은 어떤 특별한 일을합니다. https://stackoverflow.com/questions/152005/how-can-currying-be-done-in-c – Eljay

+0

그 번호는 어디에서 오는 것입니까? 컴파일 타임 상수로 작업 할 때만 가능합니다. – Jodocus

답변

1

은 내가 훨씬 더 효율적입니다 생각, 질문의 코드에서 정말 다른 또 다른 해결책을 제안한다 (하나의 std::array에 작성, 템플릿 인덱스 순서에 의해 얻은 믹서기)

#include <array> 
#include <utility> 
#include <iostream> 

template <typename T, std::size_t I0> 
int blenderH (double t, T const & arr, std::index_sequence<I0> const &) 
{ return arr[I0]; } 

template <typename T, std::size_t I0, std::size_t ... Is> 
auto blenderH (double t, T const & arr, 
       std::index_sequence<I0, Is...> const &) 
    -> std::enable_if_t<0U != sizeof...(Is), int> 
{ return (1-t) * blenderH(t, arr, std::index_sequence<(Is-1U)...>{}) 
      + t * blenderH(t, arr, std::index_sequence<Is...>{}); } 

template <typename ... Args> 
int blender (double t, Args ... as) 
{ 
    static constexpr auto size = sizeof...(Args); 

    return blenderH(t, std::array<int, size>{ { as... } }, 
        std::make_index_sequence<size>{}); 
} 

int main() 
{ std::cout << blender(.3, 23, 42, 89) << std::endl; } 

을 불행하게도이 솔루션은 C++ 14부터 (std::index_sequencestd::make_index_sequence) 작동합니다.

- 편집 -

Caleth들은 말한다.

도움이 여기에 무슨 일이 일어나고 있는지의 일부 설명. 나는 두 번째 과부하의 본문에 I0의 부족으로 혼란스러워.

나는 설명을보십시오.

std::index_sequence 값의 색인 목록이있는 BlenderH() (두 번째 오버로드)의 순환 버전이라고합니다. 5, 6, 7 및 8이라고 말하십시오. 따라서 I05이고 Is...6, 7, 8입니다.

우리는 인덱스 5, 6, 7을 먼저 가지고 6, 7, 8을 가지고 재귀 호출 을 호출해야합니다.

우리는 1 매의 값 (제 재귀 호출하므로 std::index_sequence<(Is-1U)...>)

  • 6, 7, 8Is...이다 감소 6, 7, 8에서

    • 5, 6, 7 얻는다 I0 (5) 때문에 사용 방지 할 변형 (그래서 번째의 std::index_sequence<Is...>없이.

    실제적인 관점에서 I0은 폐기 될 것으로 선언됩니다. Ther은 그것을 사용할 필요가 없습니다.마지막 인수의 수를 무시하는

    여기
  • +0

    여기에 무슨 일이 일어나고 있는지에 대한 설명이 도움이 될 것입니다. 나는 두 번째 과부하의 몸에 'I0'가 부족하여 혼란 스럽다. – Caleth

    +1

    @Caleth - 설명이 좋지 않지만 ... 대답이 수정되었습니다. – max66

    0
    template<std::size_t I> 
    using count = std::integral_constant<std::size_t, I>; 
    
    namespace details { 
    
        template<class...Args, std::size_t N, 
        typename std::enable_if<sizeof...(Args)==N, bool>::type = true 
        > 
        int Blender(count<N> drop, double t, int i, Args...args) { 
        return i; 
        } 
        template<class...Args, std::size_t N, 
        typename std::enable_if<sizeof...(Args)!=N, bool>::type = true 
        > 
        int Blender(count<N> drop, double t, int i, Args...args) { 
        return (1-t)*Blender(count<N+1>{}, t, i, args...) + t*Blender(count<N>{}, t, args...); 
        } 
    } 
    
    template <typename ...Args> 
    int Blender(double t, int first, Args... more) 
    { 
        return details::Blender(count<0>{}, first, more...); 
    } 
    
    
    static void tryit() 
    { 
        Blender(.5, 23, 42, 89); //doesn't compile 
    } 
    

    count<N> 계산됩니다.

    두 개의 details 오버로드는 N이 팩의 인수 수와 같고 (따라서 1 개의 인수가 남아 있음), 그리고 그렇지 않은 경우를 다룹니다. 그들은 SFINAE를 사용하여 파견됩니다.

    0

    제한 사항이 함수 호출이 아닌 형식 팩 공제에 있음을 알게되면 실제로 실제로 매우 쉽습니다. 우리는 단지 우리가 추론 할 수있는 타입의 팩을 사용하고 마지막 매개 변수를 해내 필요로하는 기능에서 명시 적으로 피하는 공제를 전달하는 방법이 필요합니다 :

    int Blender(double t, int i) 
    { 
        return i; 
    } 
    
    template <typename ...Args> 
        int Blender(double t, int first, Args... more); 
    
    template <typename ...Args> 
        int BlenderWithoutLast(double t, Args... more, int last) 
    { 
        return Blender(t, more...); 
    } 
    
    template <typename ...Args> 
        int Blender(double t, int first, Args... more) 
    { 
        return (1-t)*BlenderWithoutLast<Args...>(t, first, more...) + t*Blender(t, more...); 
        // all the magic happens here ^^^^^ 
    } 
    

    지금 당신의 테스트 케이스는 컴파일하고

    를 실행 나이 들어
    #include <iostream> 
    int main() 
    { 
        std::cout << Blender(.5, 23, 42, 89); 
    } 
    

    는 그 소리와 함께 작동 및 --std=c++11

    +0

    멋진! Ubi maior minor cessat. – max66

    +0

    @ max66 : 처음으로 도우미 함수를 생각해 보았을 때 어떻게 인식하는지 알아 내려고했는데, 왜냐하면 지나가는 템플릿 유형의 실제 매개 변수를 발견하지 못했기 때문입니다. 이를 위해 구조화 된 도우미 함수. –