2015-09-20 7 views
7

का वैराडिक सदस्य फ़ंक्शन मुझे एक समस्या का सामना करना पड़ रहा है जहां मैं एक विशिष्ट प्रकार के पैरामीटर पैक के साथ एक विविध सदस्य फ़ंक्शन बनाने की कोशिश कर रहा हूं।टेम्पलेट वर्ग

template <typename T> 
struct A 
{ 
    using result_type = T; 

    T operator()(T a, T b) 
    { 
     return a+b; 
    } 
}; 

template <typename Functor> 
struct B 
{ 
    using T = typename Functor::result_type; 

    T operator()(Functor &&f, T... args) 
    { 
     return f(args...); 
    } 
}; 

ऐसा लगता है कि काम करने के लिए आशा की जाती है:

A<int> a; 
B<A<int>> b; 

int result = b(a, 2, 3); // should return 5 

हालांकि मैं निम्नलिखित त्रुटियाँ मिलती है:

error: type 'T' (aka 'typename Functor::result_type') of function parameter pack does not contain any unexpanded parameter packs 
     T operator()(Functor &&f, T... args) 
            ~^~~~~~~~ 

error: pack expansion does not contain any unexpanded parameter packs 
      return f(args...); 
        ~~~~^ 

क्या उम्मीद की कार्यक्षमता को प्राप्त करने के लिए उचित तरीका क्या होगा?

उत्तर

4

एक पैरामीटर पैक केवल तभी उपयोग किया जा सकता है जब फ़ंक्शन फ़ंक्शन टेम्पलेट हो।

http://en.cppreference.com/w/cpp/language/parameter_pack से:

टेम्पलेट पैरामीटर पैक टेम्पलेट पैरामीटर कि शून्य या अधिक टेम्पलेट तर्क (गैर प्रकार, प्रकार, या टेम्पलेट्स) को स्वीकार करता है। फ़ंक्शन पैरामीटर पैक एक फ़ंक्शन पैरामीटर है जो शून्य या अधिक फ़ंक्शन तर्क स्वीकार करता है।

कम से कम एक पैरामीटर पैक वाले टेम्पलेट को एक वैरिएडिक टेम्पलेट कहा जाता है।

template <typename ... Args> 
T operator()(Functor&& f, Args... args) 
{ 
    return f(args...); 
} 

इसके अलावा, ऊपर समारोह में && के उपयोग भावना केवल अगर यह टेम्पलेट पैरामीटर है बनाता है। जब आप प्रकार टेम्पलेट पैरामीटर किया जा रहा बिना तर्क पर && उपयोग करते हैं, आप का उपयोग नहीं कर सकते हैं:

A<int> a; 
B<A<int>> b; 
int r = b(a, 2, 3); 

आप कर सकते हैं, हालांकि,

int r = b(std::move(a), 2, 3); 

का उपयोग अपने पिकअप करें। तर्क प्रकार रखें है के रूप में और std::move(a) का उपयोग करें या

template <typename ... Args> 
T operator()(Functor& f, Args... args) 
{ 
    return f(args...); 
} 

और प्रयोग

int r = b(a, 2, 3); 

अद्यतन एक सरल संदर्भ का उपयोग करने के समारोह को बदलने

आप सुनिश्चित करने के लिए एक सहायक वर्ग का उपयोग कर सकते कि सभी तर्क सही प्रकार के हैं।

template<typename ... Args> struct IsSame : public std::false_type {}; 

template<typename T> struct IsSame<T> : public std::true_type {}; 

template<typename T, typename ... Args> struct IsSame<T, T, Args...> : public std::true_type 
{ 
    static const bool value = IsSame<T, Args ...>::value; 
}; 

और उपयोग:

template <typename ... Args> 
T operator()(Functor&& f, Args... args) 
{ 
    static_assert(IsSame<T, Args...>::value, "Invalid argument type"); 
    return f(args...); 
} 
इसी के साथ

,

A<int> a; 
B<A<int>> b; 
int r = b(std::move(a), 2, 3); 

अभी भी काम करता है लेकिन

r = b(std::move(a), 2, 3.0); 

विफल रहता है।

मुझे नहीं पता कि तर्क के प्रकारों के साथ सख्त होने के कारण आपके मामले में क्या कहा जाता है। यदि आपको आवश्यकता है तो आपके पास एक तरीका है।

+0

क्या तर्क के प्रकार पर प्रतिबंध लागू करने के लिए कोई मानक तरीका नहीं है, या पैरामीटर पैक में एक विशिष्ट प्रकार का उपयोग करने के लिए कोई मानक तरीका नहीं है? अगर उत्तर नहीं है तो केवल एक चीज जो मैं कर सकता हूं वह std :: is_same के साथ एक static_assert है। – plasmacel

+0

@plasmacel, अद्यतन –

+0

एक संपूर्ण उत्तर देखें। – plasmacel

1

आपको एक तर्क पैक का उपयोग करना चाहिए। इसके अलावा, आप एक रावल्यू संदर्भ पारित करने का प्रयास क्यों करते हैं?

template <typename Functor> 
struct B 
{ 
    using T = typename Functor::result_type; 

    template<typename ...Args> 
    T operator()(Functor f, Args... args) 
    { 
     return f(args...); 
    } 
}; 

संपादित करें: आप की पुष्टि है कि सभी तर्क प्रकार टी के हैं चाहते हैं, आप एक की पुष्टि करने struct की घोषणा कर सकते हैं:

template <typename T, typename ...Pack> 
struct verify_params {}; 

template <typename T> 
struct verify_params<T> { 
    using val=void; 
}; 

template <typename T, typename ...Pack> 
struct verify_params<T,T,Pack...> { 
    using val=typename verify_params<T,Pack...>::val; 
}; 

और फिर, आप अपने कार्य करने के लिए (typename verify_params<T,Args...>::val)0; की तरह एक पंक्ति जोड़ सकते हैं ।

+0

आर्ग के प्रकार के किसी भी प्रकार नहीं हो सकता। यह typename Functor :: result_type होना चाहिए। मैं अनावश्यक प्रतियों से बचने के लिए एक सार्वभौमिक अग्रेषण संदर्भ पारित करना चाहता हूं। – plasmacel

+0

पहली समस्या के लिए, आपको पैक में तत्वों को सत्यापित करना चाहिए (मुझे इसके बारे में सोचने दें)। दूसरे के लिए, या तो 'std :: move' का उपयोग करें, या एक कॉन्स lvalue संदर्भ का उपयोग करें। – asaelr

2

एक विचार के बजाय एक std::initializer_list उपयोग करने के लिए है, जो एक ही प्रकार (के लिए बाध्य करेगा निश्चित रूप से आप शायद एक variadic टेम्पलेट और std::is_same से कुछ चतुर उपयोग के साथ इस के आसपास मिल सकती है variadic टेम्पलेट के सभी पैरामीटर के लिए एक ही प्रकार लागू करने के लिए है):

#include <algorithm> 
#include <initializer_list> 
#include <utility> 
#include <iostream> 

template <typename T> 
struct A 
{ 
    using result_type = T; 

    T operator()(std::initializer_list<result_type> const& li) 
    { 
     return std::accumulate(std::begin(li), std::end(li), 0.); 
    } 
}; 

template <typename Functor> 
struct B 
{ 
    using T = typename Functor::result_type; 

    T operator()(Functor &&f, std::initializer_list<T> args) 
    { 
     return f(args); 
    } 
}; 

int main() 
{ 
    A<int> functor; 
    B<decltype(functor)> test; 
    std::cout << test(std::move(functor), {1, 2, 3}); // displays 6 
} 

Live on Coliru

2

जैसे कुछ SFINAE चाल कर सकते हैं:

struct Foo {}; 
template<class T, class...> 
struct all_same : std::true_type 
{}; 

template<class T, class U, class... SS> 
struct all_same<T, U, SS...> 
    : std::integral_constant<bool, std::is_same<T,U>{} && all_same<T, SS...>{}> 
{}; 

फिर,

template <typename Functor> 
struct B 
{ 
    using T = typename Functor::result_type; 

    template<typename ...Args> 
    T operator()(Functor&& f, Args... args) 
    { 
     static_assert(all_same<T, Args...>{}, "all not same types"); 
     return f(args...); 
    } 
}; 

डेमो Here

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