5

मैं एक स्कैला/जावा प्रोग्रामर हूं जो स्वयं को C++ पर पुन: पेश करने की तलाश में है और C++ 0x में कुछ रोमांचक विशेषताओं को सीखता हूं। मैं स्कैला के संग्रह के आधार पर अपनी खुद की थोड़ा कार्यात्मक संग्रह लाइब्रेरी तैयार करके शुरू करना चाहता था, ताकि मैं टेम्पलेट्स की ठोस समझ प्राप्त कर सकूं। जिस समस्या में मैं चल रहा हूं वह यह है कि संकलक टेम्पलेट फ़ंक्शन ऑब्जेक्ट्स के लिए किसी भी प्रकार की जानकारी का अनुमान लगाने में सक्षम नहीं प्रतीत होता है।सी ++ 0 एक्स टेम्पलेट फ़ंक्शन ऑब्जेक्ट अनुमान

FC++ "हस्ताक्षर" का उपयोग करके इसे हल किया गया प्रतीत होता है। ये परिणाम_ टाइप टाइपनाम के समान ही प्रतीत होते हैं, और मैंने सोचा कि मुझे यह नया फ़ंक्शन सिंटैक्स का उपयोग करके मिल जाएगा। क्या कोई इस तरह की चीज को सी ++ 0x में करने का तरीका सुझा सकता है, यदि यह संभव है, या कम से कम समझाएं कि एफसी ++ इसे कैसे पूरा करने में सक्षम था? यहाँ कोड का एक टुकड़ा मैं

#include <vector> 
#include <iostream> 
#include <algorithm> 
using namespace std; 

template<class T> 
class ArrayBuffer { 
private: 
    vector<T> array; 
public: 
    ArrayBuffer(); 
    ArrayBuffer(vector<T> a) : array(a) {} 

    template<typename Fn> 
    void foreach(Fn fn) { 
     for(unsigned int i = 0; i < array.size(); i++) fn(array[i]); 
    } 

    template<typename Fn> 
    auto map(Fn fn) -> ArrayBuffer<decltype(fn(T()))> { 
     vector<decltype(fn(T()))> result(array.size()); 
     for(int unsigned i = 0; i < array.size(); i++) result[i] = fn(array[i]); 
     return result; 
    } 
}; 

template<typename T> 
class Print { 
    public: 
    void operator()(T elem) { cout<<elem<<endl; } 
}; 

template<typename T> 
class Square{ 
public: 
    auto operator()(T elem) -> T { 
     return elem * elem; 
    } 
}; 

int main() { 
    vector<int> some_list = {5, 3, 1, 2, 4}; 
    ArrayBuffer<int> iterable(some_list); 
    ArrayBuffer<int> squared = iterable.map(Square<int>()); // works as expected 
    iterable.foreach(Print<int>()); // Prints 25 9 1 4 16 as expected 
    iterable.foreach(Print()); // Is there a way or syntax for the compiler to infer that the template must be an int? 
    ArrayBuffer<int> squared2 = iterable.map(Square()); // Same as above - compiler should be able to infer the template. 
} 

उत्तर

5

के साथ चारों ओर खेल रहा था आप operator() एक टेम्पलेट बना सकते हैं भी

class Print { 
    public: 
    template<typename T> 
    void operator()(T elem) { cout<<elem<<endl; } 
}; 

तो फिर तुम Print() पारित कर सकते हैं है। ArrayBuffer<decltype(fn(T()))> में की तरह तर्क पारित करने के लिए मैं declval का उपयोग करना चाहिये, ताकि आप भी साथ गैर-डिफ़ॉल्ट constructible T

ArrayBuffer<decltype(fn(declval<T>()))> 
+0

धन्यवाद! यह पूरी तरह से काम करता है। मैंने ऑपरेटर को टेम्पलेट को स्थानांतरित करने के बारे में नहीं सोचा था। मैं भी घोषणा के बारे में टिप की सराहना करता हूं। मेरे पास एक संक्षिप्त अनुवर्ती है - क्या एक टेम्पलेटेड फ़ंक्शन पॉइंटर का उपयोग करके ऐसा करने का कोई तरीका है? उदाहरण के लिए, यदि हमारे पास टेम्पलेट प्रिंट फ़ंक्शन है, तो मैं iterable.foreach (और प्रिंट) को कॉल कर सकता हूं; मेरा मानना ​​है कि जवाब नहीं है। –

0

काम कर सकता था वहाँ एक रास्ता या वाक्य रचना संकलक अनुमान लगाने के लिए कि टेम्पलेट किसी पूर्णांक होना चाहिए के लिए है ?

समस्या की जरूरत नहीं है किसी पूर्णांक होना करने के लिए टेम्पलेट है।
यह समान रूप से मान्य है।

iterable.foreach(Print<float>()); 

आप वास्तव में क्या पूछ रहे हैं।
क्या मैं टेम्पलेट मज़ेदार को संदर्भ के आधार पर एक अलग डिफ़ॉल्ट बना सकता हूं जिसमें इसका उपयोग किया जाता है?

उत्तर नहीं है। मुझे लगता है कि हम सैद्धांतिक रूप से सरल मामलों के लिए ऐसा कर सकते हैं। हालांकि कोने के मामले जल्दी से इस अक्षम बनाते हैं। फ़ंक्शन का सही संदर्भ पूर्ण संकलन इकाई है, न केवल उस रेखा पर जहां इसे तुरंत चालू किया जाता है।

1

आप सी ++ मानक पुस्तकालय को फिर से शुरू करने लगते हैं। मैं आपके कंटेनर के बारे में बात नहीं कर रहा हूँ।
सी ++ पहले से ही काफी कार्यात्मक रूप से सुसज्जित है।

मुझे लगता है कि आप सी ++ मानक पुस्तकालय के बारे में कुछ महत्वपूर्ण बिंदु खो रहे हैं।

  • यह जेनेरिक पहली और ऑब्जेक्ट ओरिएंटेड पीछे नहीं है।
    यदि एक सामान्य तरीके से एक एग्रीग्रिम लागू किया जा सकता है तो इसे कक्षा के साथ शामिल नहीं किया जाएगा।
    ArrayBuffer::foreach == std::for_each
    ArrayBuffer::map == std::transform
  • मानक एल्गोरिदम पूरा कंटेनर के बजाय iterators पर काम करते हैं। इसे अक्सर नए सी ++ प्रोग्रामर द्वारा याद किया जाता है क्योंकि जावा और सी दोनों में अवधारणा की कमी होती है। Iterators अकेले कंटेनरों की तुलना में अधिक अभिव्यक्तिपूर्ण/लचीला हैं। Iterators arguably जाने के लिए रास्ता हैं।उस ने कहा, Ranges इटरेटर्स को व्यक्त करने के लिए बहुत अधिक रास्ता है (एक रेंज सिर्फ इटरेटर को जोड़ा गया है)।

यहां सी ++ को कार्यात्मक रूप से उपयोग करने का एक उदाहरण दिया गया है। यह भी एक अच्छा उदाहरण है कि सी # ने इटरेटर का उपयोग क्यों नहीं किया। हालांकि वे बहुत शक्तिशाली हैं, उनकी verbosity सी # के लक्षित दर्शकों को डरा रही है। जावा iterators का उपयोग नहीं करता है क्योंकि वे ऑब्जेक्ट ओरिएंटेड नहीं हैं और भाषा डिज़ाइनर शुरुआत में इसके बारे में वास्तव में गुदा थे।

struct Print 
{ 
    template<typename T> 
    void operator()(const T& t) 
    { std::cout << t << std::endl; } 
}; 

struct Squared 
{ 
    template<typename T> 
    T operator()(const T& t) 
    { return t*t; } 
}; 

int main() 
{ 
    std::vector<int> vi; 
    std::foreach(vi.begin(), vi.end(), Print()); 
    std::foreach(vi.begin(), vi.end(), [](int i){ std::cout<<i<<std::endl; }); 

    std::vector<int> vi_squared; 

    std::transform(vi.begin(), vi.end(), std::back_inserter(vi_squared), Squared()); 
    // or 
    vi_squared.resize(vi.size()); 
    std::transform(vi.begin(), vi.end(), vi_squared.begin(), Squared()); 
} 
+0

सुझावों के लिए धन्यवाद। मैं समझता हूं कि कैसे एसटीएल कुछ एल्गोरिदम को कंटेनर से अच्छे तरीके से अलग करता है। यह अभी भी कई चीजें जैसे फोल्ड, कमी, विचार, स्लाइस, फ्लैटन, फ्लैट मैप्स इत्यादि छोड़ देता है। अंत में, सी ++ में परिवर्तन विनाशकारी है। मैं उत्परिवर्तनीय संग्रह के अलावा पूरी तरह से लगातार संग्रह लागू करना चाहता हूं, और यह एसटीएल के विभाजन के डिजाइन के साथ नहीं किया जा सकता है। नक्शा कंटेनर पर एक ऑपरेशन होना चाहिए, और कंटेनर इसे लागू करने का तरीका चुनने में सक्षम होना चाहिए। –

+0

असल में, मैं इसे वापस लेता हूं। ट्रांसफॉर्म विनाशकारी प्रतीत नहीं होता है। फिर भी, मुझे लगता है कि कंटेनरों के हिस्से के रूप में संचालन करना समझ में आता है और प्रत्येक कंटेनर अपने विशिष्ट व्यवहार को लागू करने देता है। मुझे यकीन नहीं है कि मैं इस डिजाइन से कितना कोड पुन: उपयोग कर पाऊंगा, हालांकि मेरे एल्गोरिदम को पुनरावृत्ति के साथ मिश्रित किया जाएगा। मैं एक पदानुक्रम के तहत लागू किए गए किसी भी अलग संग्रह को एकजुट करने के लिए सीआरटीपी का उपयोग करने की भी उम्मीद कर रहा हूं ताकि मैं पुस्तकालय से कार्यान्वयन के बजाय एक इंटरफ़ेस प्रस्तुत कर सकूं (टेम्पलेट विधियां आभासी नहीं हो सकती हैं)। रेंज अद्भुत दिखती है - मैं लिंक की सराहना करता हूं। –

+0

जब भी आप 'std :: transform' या किसी std एल्गोरिदम पर उपयोग करते हैं तो आप अभी भी एक कंटेनर व्यवहार का विशेषज्ञ बना सकते हैं। मानचित्र विधि को उप-वर्गीकरण और ओवरराइड करने के बजाय, आप अपने कंटेनर के लिए 'std :: transform' विधि विशेष (तकनीकी रूप से आंशिक-विशेषज्ञता) विशेषीकृत करते हैं। आम तौर पर, यह परिभाषित करना कि आपका संग्रह कैसे घुमाया गया है पर्याप्त है और इटेटरेटर वास्तव में यह अच्छा करते हैं (और श्रेणियां/विचार इसे बेहतर करते हैं)। यह मेरे लिए सही लगता है। 99% समय एक नक्शा एल्गोरिदम भंडारण semantics के बारे में परवाह नहीं करता है। लेकिन अगर आपको वास्तव में वहां पहुंचने और पागल चीजें करने की ज़रूरत है तो आप विशेषज्ञ बन सकते हैं। –

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