如何编写一个可变的方法来替换链接的方法调用? [英] How to write a variadic method which replaces chained method calls?

查看:172
本文介绍了如何编写一个可变的方法来替换链接的方法调用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用一个名为 group_by 的递归地图类来建模SQL名称。



例如,gb是一个 group_by 对象,它将存储指向 foo 的指针c> std :: string , int char

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

group_by 提供 at(I const& key)存取器方法,可用于查看当前级别映射。链接在()调用以检索更深的地图工作正常。

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

PROBLEM



我想在上创建一个的替代方法: <_ c $ c> at_variadic(args const& ... args)可以在一个调用中检索更深的地图,而不需要链接。

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

但是,我遇到了一些问题。首先,我不知道如何指定返回类型,因为它取决于可变参数。也许可以使用 decltype(),不知何故?



WORKING ANSWER b
$ b

Ecatmur的回答如下介绍了一个好方法。



我不得不使用 group_by<> 的终端机来玩编译器,但下面的代码基于Ecatmur的答案,似乎与gcc 4.7.2一样正常。

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

template<类型名T,类型名... Args>
struct group_by
{
使用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<类型名称T,类型名称I,类型名称... Args>
struct group_by< T,I,Args ...>
{
使用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;
}


解决方案

链接的方法调用本质上是递归,因此您需要以递归方式实现

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

请注意,由于需要至少1个参数,可变形式至少需要2个参数。这比在 sizeof ... 上调度要容易得多,而且应该更容易阅读。


I am working on a recursive map class called group_by which models the SQL namesake.

For example, gb is a group_by object which will store pointers to foo grouped by std::string, int, and char key types, in that order.

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

group_by provides an at( I const& key ) accessor method which can be used to look inside current level map. Chaining at() calls to retrieve deeper maps works fine.

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

PROBLEM

I would like to create an alternative of at() called at_variadic( Args const& ...args ) which can retrieve deeper maps all in one call, without chaining.

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

However, I am running into some issues. First of all, I don't know how to specify the return type, since it depends on the variadic arguments. Maybe use decltype(), somehow?

WORKING ANSWER

Ecatmur's answer below outlined a good approach.

I had to play around with terminal case of group_by<> to make the compiler happy, but the code below, heavily based on Ecatmur's answer, seems to work fine with 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;
}

解决方案

Chained method calls are essentially recursive, so you need to implement at recursively:

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

Note that since at requires at least 1 argument, the variadic form takes at least 2 parameters. This is significantly easier to implement than dispatching on sizeof..., and should be easier to read.

这篇关于如何编写一个可变的方法来替换链接的方法调用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆