2012-01-11 40 views
6

मैं एक फ़ंक्शन टेम्पलेट, apply लिखना चाहता हूं, जो कुछ फ़ंक्शन f, एक पूर्णांक i, और एक पैरामीटर पैक प्राप्त करता है। apply को पैरामीटर अनपैक करने और f लागू करने की आवश्यकता है, i वें पैरामीटर, pi को छोड़कर। 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

पीआई math.h में एम_PI के रूप में उपलब्ध है। बाकी के बारे में निश्चित नहीं है, क्या आप कम इलिप्सिस के साथ कोड पोस्ट कर सकते हैं? –

+2

@ हंसपैसेंट मुझे लगता है कि ओपी का अर्थ है 'i-पैरामीटर' 'pi' –

+5

@ हंसपैसेंट सी ++ अब पूरी तरह से चला गया: आपको अब सभी कोड लिखने की आवश्यकता नहीं है! इलिप्सिस वास्तव में कोड हैं और निष्पादित किए जा रहे हैं! –

उत्तर

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

यह मेरा मूल कोड की एक त्वरित रूपांतरण है, इसलिए यह अच्छी तरह से परीक्षण नहीं किया गया है और हो सकता है नहीं यह करने के लिए नहीं इष्टतम तरीका है, लेकिन यह कम से कम (कम से कम काम करना चाहिए एक त्वरित परीक्षण के अनुसार और आप वास्तव में क्या चाहते हैं के आधार पर)। बिना टपले के ऐसा करना संभव होना चाहिए, लेकिन मुझे यह नहीं मिला है कि जी ++ के साथ संकलन करें (यह आवश्यक घोंसला वाले चरम टेम्पलेट्स की तरह प्रतीत नहीं होता है)। हालांकि करने के लिए apply बदल रहा:

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

शायद भूमि के ऊपर टपल द्वारा शुरू की सबसे अधिक से बचने जाएगा। std::get कॉल के परिणामों की सही अग्रेषण करना बेहतर होगा, लेकिन अब मैं लिखने के लिए बहुत थक गया हूं।

+0

मुझे लगता है कि यह अधिक जटिल दिखता है और यह भी काम करने के लिए 'std :: tuple' पर निर्भर करता है! निश्चित रूप से, मैं एक मानक वर्ग ('std :: enable_if') का भी उपयोग कर रहा हूं लेकिन' std :: tuple' की तुलना में 'std :: enable_if' trivial का कार्यान्वयन है। मेरे कोड का काफी हद तक वास्तव में ऑपरेशन को लागू करना और परिणामों को प्रिंट करना भी है। –

+0

@ डाइटमार कुहल: मैं अधिक जटिल भाग के साथ असहमत हूं। और 'std :: tuple' पर भरोसा करने में समस्या क्या है, अगर हम केवल वैरैडिक टेम्पलेट्स का उपयोग करने के कारण सी ++ 11 से बंधे हैं?(आवश्यक ट्यूपल ऑपरेशंस को लागू करने वाले विविध टेम्पलेट्स के अलावा भी बहुत आसान है)। तो समस्या क्या है? – Grizzly

+0

दोनों समाधान दिलचस्प हैं। उन्हें उपलब्ध कराने के लिए धन्यवाद। फिर भी, मैं निराश हूं कि सी ++ 11 में कोई और सीधा समाधान नहीं है। –

संबंधित मुद्दे