6

में तर्क के रूप में पॉलिमॉर्फिक (जेनेरिक) फ़ंक्शंस मैं एक अपेक्षाकृत सरल प्रोग्राम (वास्तव में एक कैलक्यूलेटर) विकसित कर रहा हूं। हालांकि, मैंने अपने कार्यक्रम के सभी घटकों को यथासंभव सामान्य बनाने का निर्णय लिया है क्योंकि:सी ++

  1. यह अच्छा अभ्यास है।
  2. यह चीजों को दिलचस्प रखता है।

इस कार्यक्रम के हिस्से के रूप में मैं Tuple कक्षा का उपयोग कर रहा हूं जिसे मैं लिख रहा हूं। मुझे पता है कि एक वर्ग पहले से मौजूद है, लेकिन मुझे अपने कोड पर पूरा नियंत्रण रखना पसंद है और यह केवल एक अभ्यास है।

एक बात मैं क्या करने की जरूरत एक टपल अभिव्यक्ति 'मूल्यांकनों के परिणाम युक्त में भाव (जहां भाव खुद को सामान्य कर रहे हैं) के एक टपल बदलना है। संक्षेप में, मैं (तुच्छ भागों बाहर छोड़ दिया) के साथ है:

template <class T> 
class Expression { 

    public: 
     virtual T Eval() = 0; 

    // ... 
}; 

template <class First, class ... Rest> 
class Tuple { 

    // ... 

    private: 
     First first; 
     Tuple<Rest ...> rest; 
}; 

और मैं इस तरह एक सामान्य प्रकार का एक टपल से अधिक विशेषज्ञ चाहते हैं:

template <template <class> class R, class First, class ... Rest> 
class Tuple<R<First>, R<Rest> ...> { 

    // and here is the problem: 
    Tuple<First, Rest ...> Transform(function<template<class T> T(R<T>)>); 
}; 

जो बाद मैं ऐसा कर सकता है:

template <class T> // There has to be a better way to do this 
T Eval(Expression<T>& expr){ 
    return expr.Eval(); 
} 

// ... 
Tuple<First, Rest ...> tuple = exprs.Transform(Eval); 

वहाँ कुछ स्थानों पर यहाँ है, जहाँ मुझे यकीन है कि चीजों को और एक असली विशेषज्ञ जो मुझे यहाँ से बाहर मदद कर सकता है की सराहना की होगी के बारे में जाने के लिए कैसे नहीं कर रहा हूँ कर रहे हैं। मुझे उम्मीद है कि यह कोड मामूली खामियों के कारण संकलित नहीं होगा, लेकिन यह बात नहीं है - मेरी प्राथमिक चिंता वह रेखा है जिसे मैंने चिह्नित किया है। यदि मुझे संक्षिप्त अवधि से सही तरीके से याद किया गया है तो मैंने हास्केल सीखा है यह फ़ंक्शन रैंक -2 का होना चाहिए (यदि टिप्पणी नहीं है और मैं टैग हटा दूंगा)। यह सिर्फ सही नहीं दिखता है। क्या इसे करने का कोई तरीका है?

अद्यतन:

मैं एक सामान्य operator() एक टेम्पलेट तर्क के रूप में के साथ एक functor पारित कोशिश करने की सलाह दी थी, लेकिन है कि या तो काम नहीं किया। की तरह कुछ (here देखें)

+0

'boost :: mpl :: transform' आज़माएं। –

+0

@ एनएम। - वह कार्यक्षमता प्रदान नहीं करता है जिसे मैं ढूंढ रहा हूं। – user2008934

+0

@dyp - हाँ, मैं करता हूं, यह एक शुद्ध वर्चुअल फ़ंक्शन है। लेकिन यह बात नहीं है। मुद्दा यह है कि - मैं एक सामान्य कार्य को तर्क के रूप में कैसे पास करूं? – user2008934

उत्तर

2

मुझे लगता है कि आप इसे सी ++ 14 के बिना बिल्कुल सुंदर कर सकते हैं।

Tuple(First, Rest...);    // (1) 
Tuple(First, const Tuple<Rest...>&); // (2) 

हम एक प्रकार विशेषता की जरूरत है: मुझे लगता है कि इन दो ctors मौजूद अपने Tuple कैसे निर्माण किया है, अर्थात् के बारे में कुछ बातें मान जा रहा हूँ एक समारोह है कि हम साथ बदलने रहे हैं को देखते हुए, हम पता करने की जरूरत क्या प्रकार यह पैदा करता है:

template <typename T, typename F> 
using apply_t = decltype(std::declval<F>()(std::declval<T>())); 

(भगवान मैं प्यार करता हूँ सी ++ 11)

इसी के साथ

, हम तय कर सकते हैं वापसी आसानी से टाइप करें, और यह समारोह रिकर्सिवली बुला का मामला है:

template <typename First, typename... Rest> 
struct Tuple 
{ 
    template <typename F> 
    Tuple<apply_t<First, F>, apply_t<Rest, F>...> 
    Transform(F func) 
    { 
     return {func(first), rest.Transform(func)}; // hence the need 
                // for ctor (2) 
    }; 
}; 

(पर आप कैसे लिखा निर्भर करता है आपके Tuple एक छोटी सी को बदलने के लिए है कि सिर्फ एक Tuple<>, या एक आधार मामला सिर्फ एक Tuple<apply_t<First, F>> देता है कि रिटर्न आप या एक आधार मामले की आवश्यकता नहीं हो सकता है। किसी भी तरह से, एक बड़ा सौदा नहीं)।

और आपको Tuple विशेषज्ञ भी विशेषज्ञता की आवश्यकता नहीं है। आपको बस सही मकसद में गुजरने की जरूरत है। उदाहरण के लिए:

struct Zero 
{ 
    template <typename T> 
    int operator()(T) { return 0; } 
}; 

struct Incr 
{ 
    template <typename T> 
    T operator()(T x) { return x + 1; } 
}; 

Tuple<int, double, char> tup(1, 2.0, 'c'); 
auto z = tup.Transform(Zero{}); // z is Tuple<int, int, int>{0, 0, 0} 
auto i = tup.Transform(Incr{}); // i is Tuple<int, double, char>{2, 3.0, 'd'} 

Here की एक पूर्ण कोड उदाहरण के लिए, सभी प्रकार के भी प्रवेश करने। बेशक, सी ++ 14 के साथ, हम इनलाइनों को कर सकते हैं:

auto i2 = tup.Transfom([](auto x) -> decltype(x) {return x+1; }); 
// i2 is a Tuple<int, double, char>{2, 3.0, 'd'}; 
// without the trailing decltype, it gets deduced as Tuple<int, double, int>. 
3

सी ++ 14 में सामान्य चाल कुछ index_sequence उपयोग करने के लिए है और फिर:

template<typename ... Args, size_t ... I> 
auto evaluate(Tuple<Args ...> const& t, index_sequence<I...>) 
{ 
    return make_tuple(evaluate(get<I>(t))...); 
} 

देखें, जैसे, this answer इस दृष्टिकोण का एक उदाहरण के लिए (फर्क सिर्फ इतना है कि है यहां अतिरिक्त रूप से एक फ़ंक्शन कॉल लागू किया गया है)।

इस प्रकार, क्या तुम यहाँ इस बात के लिए अपने Tuple कक्षा में की जरूरत है:

  • एक कस्टम get समारोह जो std::get की तरह ही व्यवहार करती है, अर्थात का एक कार्यान्वयन variadic सूचकांक तर्क स्वीकार करता है।
  • एक कस्टम make_tuple समारोह जो std::make_tuple की तरह ही बर्ताव करता है और अल्पविराम से अलग की गई सूची में से एक टपल निर्माण का एक कार्यान्वयन।

इसके अलावा, आप एक समारोह टेम्पलेट evaluate जो एक अभिव्यक्ति का मूल्यांकन करने में सक्षम है की आवश्यकता होती है, लेकिन मैं आपको पहले से ही इस राशि लगता है।


संपादित करें: मैं सिर्फ महसूस किया कि इसके बाद के संस्करण आप के लिए बहुत उपयोगी नहीं हो सकता है। बल्कि यह ध्यान दिया जाना चाहिए कि आप भी रिकर्सिवली ऐसा कर सकते हैं:

template<typename ... Args> 
auto evaluate(Tuple<Args ...> const& t) 
{ 
    return tuple_cat(make_tuple(evaluate(t.first)), evaluate(t.rest)); 
} 

template<typename T> auto evaluate(Tuple<T> const& t) { return evaluate(t.first); } 

फिर से, आप एक make_tuple समारोह, एक टपल concatenator tuple_cat और एक एकल अभिव्यक्ति मूल्यांकनकर्ता evaluate आवश्यकता होती है।

+0

std :: get और std :: make_tuple के लिए समकक्ष आसान है और मैंने उन्हें पहले से ही कुछ अलग परिदृश्य में लागू किया है। मैं अभी भी नहीं देखता कि ट्रांसफॉर्म फ़ंक्शन कैसे लिखना है, जो महत्वपूर्ण हिस्सा है। – user2008934

+0

@ user2008934: [यहां] (http://coliru.stacked-crooked.com/a/1383d7fbf9846ccb) एक बुनियादी कार्यान्वयन है जो आपको उस चीज़ के करीब ले जाना चाहिए जो आप करना चाहते हैं (सटीक मिलान के लिए आपको 'tuple_cat' ', जो मैं लागू करने के लिए बहुत आलसी था)। आशा करता हूँ की ये काम करेगा। – davidhigh

+0

यह सामान्य कैसे है? मैं यह नहीं देख रहा हूं कि इसे एक समान मामले में कैसे विस्तारित किया जाए (विभिन्न प्रकार की सूचियों का एक समूह कहें -> प्रत्येक सूची के योग का एक टुपल) - ऐसा लगता है कि आपको इस तरह के हर मामले के लिए इस कोड को दोहराना होगा। – user2008934