Jak napisać metodę variadic, która zastępuje łańcuchowe wywołania metod?

Pracuję nad rekurencyjną klasą map o nazwiegroup_by który modeluje nazwę SQL.

Na przykład gb to agroup_by obiekt, do którego będą przechowywane wskaźnikifoo pogrupowane wedługstd::string, int, ichar typy kluczy, w tej kolejności.

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

group_by zapewniaat( I const& key ) metoda dostępu, która może być użyta do przeglądania mapy bieżącego poziomu. Łańcuchyat() połączenia do wyszukiwania głębszych map działają dobrze.

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

PROBLEM

Chciałbym stworzyć alternatywęat() nazywaat_variadic( Args const& ...args ) które mogą pobierać głębsze mapy za jednym razem, bez łączenia łańcuchów.

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

Mam jednak pewne problemy. Po pierwsze, nie wiem, jak określić typ powrotu, ponieważ zależy on od argumentów zmiennoprzecinkowych. Może użyćdecltype(), jakoś?

ODPOWIEDŹ PRACY

Odpowiedź Ecatmur poniżej nakreśliłem dobre podejście.

Musiałem się bawić z obudową terminalagroup_by<> aby kompilator był szczęśliwy, ale poniższy kod, mocno oparty na odpowiedzi Ecatmur, wydaje się działać poprawnie z gcc 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;
}

questionAnswers(1)

yourAnswerToTheQuestion