2013-02-18 17 views
7

मैं group_by नामक रिकर्सिव मैप क्लास पर काम कर रहा हूं जो एसक्यूएल नेमकेक मॉडल करता है।एक वैरिएड विधि कैसे लिखें जो जंजीर विधि कॉल को प्रतिस्थापित करता है?

उदाहरण के लिए, जीबी एक group_by वस्तु जो इसी क्रम में std::string, int, और char कुंजी प्रकार के आधार पर वर्गीकृत foo की ओर इशारा संग्रहीत करेगा है।

group_by<foo,std::string,int,char> gb; 

group_by एक at(I const& key) एक्सेसर विधि है जो मौजूदा स्तर नक्शा अंदर देखने के लिए इस्तेमाल किया जा सकता प्रदान करता है। चेनिंग at() गहरे नक्शे को पुनर्प्राप्त करने के लिए कॉल ठीक काम करता है।

auto& v = gb.at(k1).at(k2).at(k3).get_vec(); 

समस्या

मैं चेनिंग बिना, at_variadic(Args const& ...args) बुलाया at() का एक वैकल्पिक जो एक कॉल में गहरी नक्शे प्राप्त कर सकते हैं सब बनाना चाहेंगे।

auto& w = gb.at_variadic(k1, k2); 
auto& x = gb.at_variadic(k1, k2, k3); 

हालांकि, मैं कुछ मुद्दों में भाग रहा हूं। सबसे पहले, मुझे नहीं पता कि वापसी प्रकार कैसे निर्दिष्ट करें, क्योंकि यह विविध तर्कों पर निर्भर करता है। शायद decltype() का उपयोग करें, किसी भी तरह?

काम उत्तर

Ecatmur's answer below एक अच्छा दृष्टिकोण को रेखांकित किया।

मुझे कंपाइलर को खुश करने के लिए group_by<> के टर्मिनल केस के साथ खेलना पड़ा, लेकिन नीचे दिया गया कोड, इक्टामूर के उत्तर पर आधारित, जीसीसी 4.7.2 के साथ ठीक काम करता है।

#include <cassert> 
#include <map> 
#include <vector> 
#include <iostream> 

template< typename T, typename... Args > 
struct group_by 
{ 
    using child_type = T; 

    std::vector<T*> m_vec; 

    void insert(T* t) 
    { 
     m_vec.push_back(t); 
    } 

    child_type& 
    at(size_t i) 
    { 
     return *m_vec[i]; 
    } 
}; 

template< typename T, typename I, typename... Args > 
struct group_by<T,I,Args...> 
{ 
    using child_type = group_by<T,Args...>; 

    std::map<I,child_type> m_map; 

    void insert(T* t) 
    { 
     m_map[ *t ].insert(t); 
    } 

    child_type& at(I const& key) 
    { 
    return m_map.at(key); 
    } 

    template<typename... Ks> 
    auto 
    at(I const& i, Ks const&...ks) 
    -> decltype(m_map.at(i).at(ks...)) 
    { 
     return m_map.at(i).at(ks...); 
    } 
}; 

// ----------------------------------------------------------------------------- 

struct foo 
{ 
    std::string s; 
    int   i; 
    char   c; 

    operator std::string() const { return s; } 
    operator int  () const { return i; } 
    operator char  () const { return c; } 

    bool operator==(foo const& rhs) const 
    { 
     return s==rhs.s && i==rhs.i && c==rhs.c; 
    } 
}; 

int main(int argc, char* argv[]) 
{ 
    foo f1{ "f1", 1, 'z' }; 
    foo f2{ "f2", 9, 'y' }; 
    foo f3{ "f3", 3, 'x' }; 
    foo f4{ "f1", 4, 'k' }; 

    group_by<foo,std::string,int,char> gb; 

    gb.insert(&f1); 
    gb.insert(&f2); 
    gb.insert(&f3); 
    gb.insert(&f4); 

    std::string k1{ "f1" }; 
    int   k2{ 1 }; 
    char  k3{ 'z' }; 

    auto& a = gb.at(k1).at(k2).at(k3).at(0); 
    auto& b = gb.at(k1).at(k2).m_map; 
    auto& c = gb.at(k1).m_map; 
    auto& d = gb.at(k1, k2).m_map; 
    auto& e = gb.at(k1, k2, k3).m_vec; 
    auto& f = gb.at(k1, k2, k3, 0); 

    assert(a==f1); 
    assert(b.size()==1); 
    assert(c.size()==2); 
    assert(d.size()==1); 
    assert(e.size()==1); 
    assert(f==f1); 

    return 0; 
} 

उत्तर

4

जंजीर विधि कॉल अनिवार्य रूप से पुनरावर्ती कर रहे हैं, ताकि आप at रिकर्सिवली लागू करने की आवश्यकता:

child_type& at(I const& key) { 
    return m_map.at(key); 
} 

template<typename J, typename... Ks> 
auto at(const I &i, const J &j, const Ks &...ks) 
-> decltype(m_map.at(i).at(j, ks...)) { 
    return m_map.at(i).at(j, ks...); 
} 

ध्यान दें कि जब से at कम से कम 1 तर्क की आवश्यकता है, variadic प्रपत्र कम से कम 2 पैरामीटर लेता है। यह sizeof... पर प्रेषण से लागू करने के लिए काफी आसान है, और इसे पढ़ने में आसान होना चाहिए।

+0

+1 tyvm - अभी यह कोशिश करेगा – kfmfe04

+0

क्या आपने यह कोशिश की है? यह संकलित प्रतीत नहीं होता है ... –

+0

@AndyProwl आप सही हैं - मुझे इसे काम करने के लिए इसके साथ खेलना पड़ा। इसे अभी साफ करो। पूरा होने पर ओपी अपडेट होगा। उसका जवाब मेरे लिए काम करने के लिए पर्याप्त था। – kfmfe04

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