5

मैं सी में एक कार्यात्मक नक्शा कार्यान्वयन ++ टेम्पलेट का उपयोग कर लिखने की कोशिश करने का फैसला किया है, और यह है कि मैं क्या लेकर आए हैं है:कार्यात्मक सी ++ टेम्पलेट दुरुपयोग के माध्यम से

template < 
    class U, 
    class V, 
    template <class> class T 
> 

class T<V> WugMap(
    class T<U>::const_iterator first, 
    class T<U>::const_iterator second, 
    V (U::*method)() const) 

{ 
    class T<V> collection; 
    while (first != second) 
    { 
     collection.insert(collection.end(), ((*(first++)).*method)()); 
    } 
    return collection; 
} 

अब यह सब ठीक है और बांका है, और यहां तक ​​कि संकलन भी। समस्या यह है कि, मुझे नहीं पता कि वास्तव में इसे कैसे कॉल करें।

prog.cpp:42: error: no matching function for call to 
‘WugMap(__gnu_cxx::__normal_iterator<Container*, std::vector<Container, 
std::allocator<Container> > >, __gnu_cxx::__normal_iterator<Container*, 
std::vector<Container, std::allocator<Container> > >, int (Container::*)()const)’ 

जहां तक ​​मेरा बता सकते हैं, सभी तर्क सही हैं:

अनुभवहीन तरह से कोशिश कर रहा है निम्न त्रुटि अर्जित करता है। जीसीसी किसी भी विकल्प का सुझाव नहीं दे रहा है, जो मुझे विश्वास दिलाता है कि WugMap की मेरी परिभाषा संदिग्ध है, लेकिन यह ठीक से संकलित है, इसलिए मैं खो गया हूं। क्या कोई मुझे इस silliness के माध्यम से मार्गदर्शन कर सकते हैं?

यदि कोई ऐसा कार्य लिखने का बेहतर तरीका सुझा सकता है जो किसी भी प्रकार के ऑब्जेक्ट वाले किसी भी प्रकार के संग्रह का उपभोग करने में सहायता करेगा, तो मैं इसे बदलना चाहूंगा।

Here's my ideone so far.

मैं वर्तमान में Ideone, जो सी ++ 03, जीसीसी 4.3.4 उपयोग कर रहा है उपयोग कर रहा हूँ।

परिशिष्ट 1

सी ++ 11 में यह संभव है? यह संकेत दिया गया है कि यह है। मुझे पता है कि सी ++ 11 में टेम्पलेट्स अलग-अलग तर्कों की संख्या का समर्थन करते हैं, इसलिए मैं इसके अनुरूप भी अपनी आवश्यकताओं को संशोधित करूंगा। मैं कुछ लिख में प्रयास के एक बिट डाल देता हूँ, लेकिन इस बीच में, यहाँ आवश्यकताओं कि मैं तलाश कर रहा हूँ कर रहे हैं:

C2<V, ...> map(const C1<U, ...>&, V (U::*)(...), ...) 
:

  • निम्नलिखित की तरह एक हस्ताक्षर कुछ है चाहिए

    यह कुछ संग्रह सी 1 ले रहा है, जिसमें टाइप यू के तत्व शामिल हैं, संदर्भ के अनुसार कुछ डिफ़ॉल्ट पैरामीटर के साथ बनाया गया है, और कुछ सदस्य फ़ंक्शन (वी को वापस लौटना और अज्ञात प्रकार के कुछ तर्क लेना) लेना, और फिर लेना , क्रम में, सदस्यों के कार्य को पारित करने के लिए तर्क। फ़ंक्शन आखिरकार प्रकार V2 का संग्रह लौटाएगा जिसमें टाइप वी के तत्व होते हैं और डिफ़ॉल्ट पैरामीटर की अज्ञात संख्या के साथ प्रारंभ किया जा रहा है।

  • chainable होना चाहिए:

    vector<int> herp = map(
            map(
             set<Class1, myComparator>(), 
            &Class1::getClass2, 2, 3), 
            &Class2::getFoo); 
    
  • बोनस अंक अगर मैं टेम्पलेट तर्क या किसी अन्य अतिरिक्त शब्दाडंबर जब इसे का उपयोग करने के लिए नहीं है।

std::transform महान है, लेकिन chainable नहीं है।

+1

क्या यह एक कंटेनर होने की आवश्यकता है? ['std :: transform'] (http://www.cplusplus.com/reference/algorithm/transform/)' में पहले से ही यह इटरेटर के साथ करता है। –

+0

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

+0

@ डीईपी: आप जानते हैं, इसके साथ कुछ करने के लिए हो सकता है, हालांकि वास्तव में, मैं समझ नहीं सकता। 'वर्ग' या 'टाइपनाम' का उपयोग करने के बारे में कुछ प्रकार के सूक्ष्म नियम हैं जो टेम्पलेट-टेम्पलेट्स शामिल होने तक खेल में नहीं आते हैं। यह समझा सकता है कि इसकी संकलन क्यों हो रही है लेकिन एक समारोह के रूप में नहीं देखा जा रहा है। – Wug

उत्तर

4

टेम्पलेट तर्क कभी भी नेस्टेड प्रकारों से नहीं लिया जा सकता है। भले ही U और V सदस्य फ़ंक्शन पॉइंटर से घटाया जा सकता है, आप टेम्पलेट प्रकार T को कम करने में सक्षम नहीं होंगे।

स्पष्ट रूप ideone के लिए लिंक के रूप में टेम्पलेट तर्क को निर्दिष्ट या तो काम नहीं करता है (मैं ऊपर बयान लिखने से पहले लिंक नहीं था), जिसका मुख्य कारण std::vector के लिए टेम्पलेट तर्क बस एक ही प्रकार T नहीं हैं!std::vector एक मूल्य प्रकार और आवंटक प्रकार लेता है। चीजों को फिक्सिंग काफी बदसूरत हो रही है:

#include <vector> 
#include <iostream> 

using namespace std; 

class Container 
{ 
public: 
    Container() {} 
    Container(int _i) : i(_i) {} 

    int get_i() const {return i;} 

    int i; 
}; 

    template < 
     class U, 
     class V, 
     template <typename...> class T 
    > 

    T<V> WugMap(
     typename T<U>::const_iterator first, 
     typename T<U>::const_iterator second, 
     V (U::*method)() const) 
    { 
     T<V> collection; 
     while (first != second) 
     { 
      collection.insert(collection.end(), ((*(first++)).*method)()); 
     } 
     return collection; 
    } 

int main() 
{ 
    vector<Container> containers; 
    for (int i = 0; i < 10; ++i) containers.push_back((Container(i))); 

    WugMap<Container, int, std::vector>(
     containers.begin(), containers.end(), &Container::get_i); 
} 
+1

वह इसे कम नहीं कर रहा है, वह स्पष्ट रूप से इसे निर्दिष्ट कर रहा है: 'WugMap <कंटेनर, int, वेक्टर > (...); ' –

+0

यह इंगित करेगा कि मैं 'WugMap <कंटेनर, int, वेक्टर> (...)' के साथ टेम्पलेट तर्कों को स्पष्ट रूप से निर्दिष्ट करने में सक्षम हूं, लेकिन यह या तो काम नहीं करता है। – Wug

+0

मैं इसके बजाय पैरामीटर और प्रयुक्त वैरिएडिक्स को हटाने के लिए कोड में बदल गया। –

2

वास्तव में सुनिश्चित नहीं हूं कि यह एक जवाब होना चाहिए, लेकिन बिल्ली:

std::vector<std::string> src = f(); 
std::vector<std::string::size_type> sizes; 
sizes.reserve(src.size()); 
// Actual transformation: 
std::transform(src.begin(), src.end(), std::back_inserter(sizes), 
       [](std::string const& s) { return s.size(); }); 

इसी बातें मैन्युअल रूप से किया जा सकता है, लेकिन वहाँ वास्तव में पुनर्रचना का कोई मतलब नहीं है पुनर्निर्मित पहिया।

क्या std::transform मामले में अलग है के रूप में, यह इतना कसकर प्रकार बाध्य करने की कोशिश नहीं करता है, यह पहली बार दो तर्क, तीसरा तर्क के लिए और तीसरे के लिए Functor के लिए Iter1 लेता है। Iter1 और गारंटी देने के लिए इंटरफ़ेस पर कोई चेक नहीं है, यह उसी प्रकार के कंटेनर में इटरेटर हैं, या Functor पहले कंटेनर में मान प्रकार से दूसरे प्रकार के मान प्रकार में बदल जाएगा।

+0

पूरा बिंदु std :: transform का उपयोग नहीं करना था क्योंकि यह वैसे ही व्यवहार नहीं करता जिस तरह से मैं चाहता था, और चूंकि यह पहिया को फिर से शुरू करने का अभ्यास ठीक था। – Wug

+0

'std :: transform' का क्या हिस्सा काम नहीं करता है जैसा आप चाहते हैं? 'ट्रांसफॉर्म' से शुरू करना और स्क्रैच से शुरू करने से आपकी आवश्यकताओं का समर्थन करने के लिए इसे बेहतर बनाना आसान हो सकता है (विशेष रूप से 'ट्रांसफॉर्म' के तर्कों पर कम सख्त आवश्यकताएं एक अच्छा लाभ है जो आपके दृष्टिकोण में मौजूद नहीं है -> के लिए उदाहरण इनपुट और आउटपुट के लिए कंटेनर मिश्रण: 'वेक्टर' से 'सेट' उत्पन्न करना –