2013-02-18 21 views
7

SQL adlarını kullanan group_by adlı yinelemeli bir harita sınıfında çalışıyorum. ÖrneğinZincirleme yöntem çağrılarının yerini alan değişken bir yöntem nasıl yazılır?

, gb bu sırayla, std::string, int ve char kilit türlerine göre gruplandırılmış foo işaretçiler depolayacak bir group_by amacıdır.

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

group_by akım seviyesi haritası içine bakmak için kullanılabilecek bir at(I const& key) erişimci yöntem sağlar. at() numaralı zincirleme, daha derin haritaların alınmasını gerektiriyor.

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

SORUN

Ben zincirleme olmadan bir çağrıda daha derin Haritalar hizmetini alabilir at_variadic(Args const& ...args) denilen at() bir alternatif yaratmak istiyoruz

.

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

Ancak, bazı sorunlarla çalıştırıyorum. Her şeyden önce, dönüş türünü nasıl tanımlayacağımı bilmiyorum, çünkü değişken değişkenlere bağlı. Belki bir şekilde decltype() kullanın?

ÇALIŞMA CEVAP

Ecatmur's answer below iyi bir yaklaşım ortaya koydu.

Derleyiciyi mutlu etmek için group_by<> terminal durumu ile uğraşmak zorunda kaldım, ancak Ecatmur'un yanıtını esas alan aşağıdaki kod gcc 4.7.2 ile iyi çalışıyor gibi görünüyor.

#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; 
} 

cevap

4

Zincirli yöntem çağrıları esasen özyinelemeli, bu yüzden yinelemeli at uygulamak gerekir: at en az 1 bağımsız değişken gerektirir çünkü variadic formu en az 2 parametre alır

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...); 
} 

Not söyledi. Bu uygulama, sizeof... numaralı telefondan verilenden daha kolay uygulanır ve okunması daha kolay olmalıdır.

+0

+1 tyvm - şimdi bunu deneyeceğim – kfmfe04

+0

Bunu denediniz mi? Bu derleme görünmüyor ... –

+0

@AndyProwl haklısın - Çalışmak için onunla oynamak zorunda kaldım. Şimdi temizliyorum. İşlem tamamlandığında OP'yi günceller. Cevabı, çalışmam için yeterliydi. – kfmfe04

İlgili konular