2012-01-11 2 views
6

기능 템플릿 apply을 작성하고 싶습니다. 일부 기능 f, 정수 i 및 매개 변수 팩을 수신합니다. apply은 번째 매개 변수 pi을 제외하고 매개 변수의 압축을 풀고 f을 적용해야합니다. pi의 경우 f의 매개 변수로 전달하기 전에 다른 함수 g을 호출해야합니다.매개 변수 팩을 분할하는 방법?

왼쪽 매개 변수 팩을 i 매개 변수로, 오른쪽으로 매개 변수 팩을 분할하는 방법이 필요합니다. 이것이 가능한가? 코드에서 :

template<int i, typename Function, typename... Parms> 
    void apply(Function f, Parms... parms) 
{ 
    auto lhs = // what goes here? 
    auto pi = // what goes here? 
    auto rhs = // what goes here? 

    f(lhs..., g(pi), rhs...); 
} 
+2

pi는 math.h에서 M_PI로 사용할 수 있습니다. 나머지 부분에 대해서는 잘 모르겠지만 줄임표가 적은 코드를 게시 할 수 있습니까? –

+2

@HansPassant 나는 OP가'pi '에 의해'ith-parameter'를 의미한다고 생각한다. –

+5

@HansPassant C++가 이제는 모든 방향으로 나아 갔다 : 더 이상 모든 코드를 작성할 필요가 없다! 줄임표는 실제로 코드이며 실행 중입니다! –

답변

3

확인을 클릭하십시오! 그것 정말 못생긴하지만 서둘러에서 좋은 버전으로 올 수 없었다;) 물건의 대부분은 늪지 표준 템플릿 전문입니다. 가장 큰 문제는 적절한 크기의 정수 목록을 만드는 것입니다. 나는 내가 좋은 버전을 생각해 냈지만 어떻게 든 나는 내가했던 것을 상기 할 수 없다는 것을 상기하는 듯하다. 즐겨!

#include <iostream> 
#include <utility> 

// printing the values 
void print_args() {} 
template <typename F> void print_args(F f) { std::cout << f; } 
template <typename F, typename... T> 
void print_args(F f, T... args) 
{ 
    std::cout << f << ", "; 
    print_args(args...); 
} 

// the function object to be called: 
struct Functor 
{ 
    template <typename... T> 
    void operator()(T... args) 
    { 
     std::cout << "f("; 
     print_args(args...); 
     std::cout << ")\n"; 
    } 
}; 

// conditionally apply g(): 
template <typename T> T g(T value) { return 1000 + value; } 
template <int i, int j, typename T> 
typename std::enable_if<i != j, T>::type forward(T t) { return t; } 
template <int i, int j, typename T> 
typename std::enable_if<i == j, T>::type forward(T t) { return g(t); } 

// create a series of integers: 
template <int... Values> struct values {}; 

template <int Add, typename> struct combine_values; 
template <int Add, int... Values> 
struct combine_values<Add, values<Values...>> 
{ 
    typedef values<Values..., Add> type; 
}; 

template <int Size> struct make_values; 
template <> struct make_values<0> { typedef values<> type; }; 
template <int Size> 
struct make_values 
{ 
    typedef typename combine_values<Size, typename make_values<Size -1>::type>::type type; 
}; 

// applying f(t...) except for ti where g(ti) is called 
template <int i, int... Values, typename Function, typename... T> 
void apply_aux(values<Values...>, Function f, T... t) 
{ 
    f(forward<i, Values>(t)...); 
} 

template <int i, typename Function, typename... T> 
void apply(Function f, T... t) 
{ 
    apply_aux<i>(typename make_values<sizeof...(T)>::type(), f, t...); 
} 

int main() 
{ 
    apply<3>(Functor(), 1, 2, 3, 4, 5, 6, 7, 8); 
    apply<4>(Functor(), 1, 2, 3, 4, 5, 6, 7, 8); 
    apply<5>(Functor(), 1, 2, 3, 4, 5, 6, 7, 8); 
} 
+0

이것으로 끝났다. 감사! –

3

사실 조금 전에 비슷한 코드를 작성했습니다. 그래서 다음과 같은 코드를 시도 :

template<unsigned N, unsigned M> 
struct call_up_impl{ 
    template<class Func, class Mutator, class Tuple, class... Args> 
    static void do_call(const Func& func, const Mutator& mutator, const Tuple& args, Args&&... unpacked_args) { 
     call_up_impl<N-1, M>::do_call(func, mutator, args, std::get<N-1>(args), std::forward<Args>(unpacked_args)...); 
    } 
}; 

template<unsigned M> 
struct call_up_impl<0, M> { 
    template<class Func, class Mutator, class Tuple, class... Args> 
    static void do_call(const Func& func, const Mutator&, const Tuple&, Args&&... unpacked_args) { 
     func(std::forward<Args>(unpacked_args)...); 
    } 
}; 
template<unsigned M> 
struct call_up_impl<M, M> { 
    template<class Func, class Mutator, class Tuple, class... Args> 
    static void do_call(const Func& func, const Mutator& mutator, const Tuple& args, Args&&... unpacked_args) { 
     call_up_impl<M-1, M>::do_call(func, mutator, args, mutator(std::get<M-1>(args)), std::forward<Args>(unpacked_args)...); 
    } 
}; 
template<int i, typename Function, typename... Parms> 
void apply(Function f, Parms... parms) { 
     std::tuple<Parms...> t(parms...); 
     call_up_impl<std::tuple_size<decltype(t)>::value, i + 1>::do_call(f, &g, t); 
} 

이 내 원래 코드의 빠른 적응이다, 그래서이 작업을 수행 할 수없는 최적의 방법을 철저하게 테스트 및 아마되지 않지만 적어도 (적어도 작동합니다 빠른 테스트에 따라 정확히 원하는대로). 튜플없이이 작업을 수행 할 수 있어야하지만 g ++로 컴파일 할 필요가 없습니다 (중첩 된 가변 템플릿이 필요하지는 않은 것 같습니다). 아마 튜플에 의해 도입 된 오버 헤드의 대부분을 피할 수

template<int i, typename Function, typename... Parms> 
void apply(Function f, Parms&&... parms) { 
     std::tuple<Parms&&...> t(std::forward<Parms>(parms)...); 
     call_up_impl<std::tuple_size<decltype(t)>::value, i + 1>::do_call(f, &g, t); 
} 

그러나에 apply을 변경. std::get 호출의 결과를 올바르게 전달하는 것이 더 좋을 지 모르지만, 나는 지금 그 일을 처리하는 데 너무 지쳤습니다.

+0

이게 더 복잡해 보이고 모든 작업을 수행하는'std :: tuple'에 달려 있다고 생각합니다! 물론, 표준 클래스 ('std :: enable_if')도 사용하고 있지만'std :: tuple'과 비교해 보면'std :: enable_if'를 구현하는 것이 간단합니다. 꽤 많은 코드가 실제로 작업을 적용하고 결과를 인쇄합니다. –

+0

@ DietmarKühl : 나는 더 복잡한 부분을 보는 것에 동의하지 않습니다. 그리고 어쨌든 variadic 템플릿을 사용하기 때문에 C++ 11에 바인딩 된 경우'std :: tuple'에 의존하는 문제는 무엇입니까?(필요한 튜플 연산을 구현하는 가변성 템플릿 외에도 매우 쉽습니다.) 문제가 무엇입니까? – Grizzly

+0

두 가지 솔루션 모두 흥미 롭습니다. 그들을 제공 주셔서 감사합니다. 여전히 C++ 11에서는 더 이상 직접적인 해결책이 없다는 점에 실망합니다. –