私はgroup_by
、SQLの同名のモデルをモデル化するという再帰マップクラスに取り組んでいます。
たとえば、gbは、、、、およびキータイプでグループ化されたポインタをこの順序で格納するgroup_by
オブジェクトです。foo
std::string
int
char
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();
問題
連鎖することなく、1回の呼び出しでより深いマップをすべて取得できるat()
calledの代替案を作成したいと思います。at_variadic( Args const& ...args )
auto& w = gb.at_variadic( k1, k2 );
auto& x = gb.at_variadic( k1, k2, k3 );
しかし、私はいくつかの問題に直面しています。まず、可変個引数に依存するため、戻り型を指定する方法がわかりません。多分decltype()
、どういうわけか使用しますか?
ワーキングアンサー
以下のEcatmurの回答は、優れたアプローチの概要を示しています。
コンパイラを満足させるためにのターミナルケースをgroup_by<>
いじくり回さなければなりませんでしたが、以下のコードは、Ecatmurの回答に大きく基づいており、gcc4.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;
}