2017-10-02 15 views
7

दो या दो से अधिक उदाहरण कार्यों को देखते हुए, क्या टेम्पलेट कोड लिखना संभव है जो टेम्पलेट पैरामीटर के रूप में प्रदान किए गए फ़ंक्शन के तर्कों को कम करने में सक्षम होगा?फंक्शन पॉइंटर से तर्क सूची कैसे घटाएं?

यह प्रेरित उदाहरण है:

void do_something(int value, double amount) { 
    std::cout << (value * amount) << std::endl; 
} 

void do_something_else(std::string const& first, double & second, int third) { 
    for(char c : first) 
     if(third/c == 0) 
      second += 13.7; 
} 

template<void(*Func)(/*???*/)> 
struct wrapper { 
    using Args = /*???*/; 
    void operator()(Args&& ... args) const { 
     Func(std::forward<Args>(args)...); 
    } 
}; 

int main() { 
    wrapper<do_something> obj; //Should be able to deduce Args to be [int, double] 
    obj(5, 17.4); //Would call do_something(5, 17.4); 
    wrapper<do_something_else> obj2; //Should be able to deduce Args to be [std::string const&, double&, int] 
    double value = 5; 
    obj2("Hello there!", value, 70); //Would call do_something_else("Hello there!", value, 70); 
} 

/*???*/ के दोनों उपयोगों में, मैं बाहर काम करने के क्या मैं वहाँ डाल सकता है कि कोड के इस प्रकार के लिए सक्षम होगा कोशिश कर रहा हूँ।

निम्नलिखित काम करने के लिए, Args की वजह से प्रकट नहीं होता है इसके पहले उपयोग करने से पहले (मैं क्या ग्रहण करने के लिए है के साथ के अलावा कई वाक्यविन्यास त्रुटियों कर रहे हैं) में परिभाषित नहीं किया जा रहा है, और यहां तक ​​कि अगर यह किया, मैं अभी भी तलाश कर रहा हूँ एक संस्करण है कि खुद को प्रकार के स्पष्ट लेखन की आवश्यकता नहीं है:

template<void(*Func)(Args ...), typename ... Args) 
struct wrapper { 
    void operator()(Args ...args) const { 
     Func(std::forward<Args>(args)...); 
    } 
}; 

wrapper<do_something, int, double> obj; 
+0

आप [std :: समारोह] (मतलब http://en.cppreference.com/w/ सीपीपी/उपयोगिता/कार्यात्मक/समारोह)? – bolov

+0

@bolov जो मैं विशेष रूप से ढूंढ रहा हूं वह उपलब्ध 'फंक्शन' से 'Args' को कम करने का एक तरीका है। 'std :: function' उन प्रकारों को टाइप पैरामीटर सूची में स्पष्ट रूप से निर्दिष्ट करके फ़ंक्शन पॉइंटर्स से मेल खाता है। – Xirema

+0

क्या आप सी ++ 17 स्वीकार करते हैं? विंक विंक – bolov

उत्तर

5

सी ++ के साथ 17 हम जो संभव बनाने Wrapper<do_something> w{} वाक्य रचना 1) ऑटो टेम्पलेट गैर प्रकार पैरामीटर हो सकता है।

Args... को कम करने के लिए आप specialization के साथ ऐसा कर सकते हैं।

template <auto* F> 
struct Wrapper {}; 

template <class Ret, class... Args, auto (*F)(Args...) -> Ret> 
struct Wrapper<F> 
{ 
    auto operator()(Args... args) const 
    { 
     return F(args...); 
    } 
}; 
Wrapper<do_something> w{}; 
w(10, 11.11); 

1) सी ++ के बिना 17 यह Wrapper<do_something> w{} अच्छा वाक्य रचना के लिए असंभव है।

सबसे अच्छा तुम कर सकते हो

है:

template <class F, F* func> 
struct Wrapper {}; 

template <class Ret, class... Args, auto (*F)(Args...) -> Ret> 
struct Wrapper<Ret (Args...), F> 
{ 
    auto operator()(Args... args) const 
    { 
     return F(args...); 
    } 
}; 
Wrapper<declype(do_something), do_something> w{}; 
+0

आपका उदाहरण कोड जीसीसी में संकलित नहीं है: https://godbolt.org/g/3WEksw – Xirema

+1

@Xirema C++ 17 कार्यान्वयन के शुरुआती चरणों में है। क्लैंग बिना किसी समस्या के संकलित कर सकते हैं: https://godbolt.org/g/DyArxa – bolov

4
के साथ सी ++ 17

, तो आप ऐसा कर सकते हैं:

template <auto FUNC, typename = decltype(FUNC)> 
struct wrapper; 

template <auto FUNC, typename RETURN, typename ...ARGS> 
struct wrapper<FUNC, RETURN (*)(ARGS...)> { 
    RETURN operator()(ARGS ...args) { 
     return FUNC(args...); 
    } 
}; 

मैं WF से इस तकनीक सीखा है ' एस answer

+0

बोलोव ने अपना समाधान तय किया, और वास्तव में मुझे यह समाधान अब बेहतर पसंद है। – geza

2

सी ++ 17 संस्करण का और सुधार: कम टेम्पलेट pa rameters और उचित noexcept एनोटेशन:

template<auto VFnPtr> struct 
wrapper; 

template<typename TResult, typename... TArgs, TResult (* VFnPtr)(TArgs...)> struct 
wrapper<VFnPtr> 
{ 
    TResult 
    operator()(TArgs... args) const noexcept(noexcept((*VFnPtr)(::std::forward<TArgs>(args)...))) 
    { 
     return (*VFnPtr)(::std::forward<TArgs>(args)...); 
    } 
}; 
0

सी ++ के साथ 11 यदि आप एक टेम्प्लेटेड make_wrapper सहायक समारोह पर विचार कर सकते हैं। हालांकि, इस दृष्टिकोण के साथ फ़ंक्शन पॉइंटर टेम्पलेट पैरामीटर नहीं है। इसके बजाय, समारोह सूचक गैर स्थैतिक डेटा सदस्य द्वारा "किया" है f_ कहा जाता है कि निम्न उदाहरण में:

#include <iostream> 

void do_something(int value, double amount) { 
    std::cout << (value * amount) << std::endl; 
} 

void do_something_else(std::string const& first, double & second, int third) { 
    for(char c : first) 
    if(third/c == 0) 
     second += 13.7; 
} 

template<class Ret, class... Args> 
using function_pointer = Ret(*)(Args...); 

template<class Ret, class... Args> 
struct wrapper { 
    using F = function_pointer<Ret, Args...>; 

    F f_; 

    explicit constexpr wrapper(F f) noexcept : f_{f} {} 

    template<class... PreciseArgs>// not sure if this is required 
    Ret operator()(PreciseArgs&&... precise_args) const { 
    return f_(std::forward<PreciseArgs>(precise_args)...); 
    } 
}; 

template<class Ret, class... Args> 
constexpr auto make_wrapper(
    function_pointer<Ret, Args...> f 
) -> wrapper<Ret, Args...> { 
    return wrapper<Ret, Args...>(f); 
} 

int main() { 
    constexpr auto obj = make_wrapper(do_something); 
    obj(5, 17.4); 
    constexpr auto obj2 = make_wrapper(do_something_else); 
    double value = 5; 
    obj2("Hello there!", value, 70); 

    return 0; 
} 
संबंधित मुद्दे