0

我有一个适用于 2 个参数的 functor_wrapper 类,我无法将其泛化为可变参数模板参数。

特别是,在将 2 个参数中的这一行转换为可变参数时,我无法正确获取语法:

2 参数代码

return m_cb( dynamic_cast<T const&>( t ), dynamic_cast<U const&>( u ));

破碎的可变参数代码

return m_cb( dynamic_cast<I const&>( t ), 
                            dynamic_cast<typename... const& Cs>( u... ));

对于任何想知道的人,这个包装类是 multiple_dispatch 类的一部分。为了向客户端提供通用类型/接口,我有这个 Functor_Wrapper 类和 operator() ,它采用父类类型。调度时,我通过dynamic_cast<>将参数向下转换为正确的类型。

更新

我刚刚意识到我还有另一个问题:我的虚拟 operator()Parent_Functor_Wrapper需要转换为 n 个参数,P const&所以我需要以某种方式展开签名!

这同样适用于 operator() in 的具体实现Functor_Wrapper

更新 2

发布完整的代码,以便更好地理解编程上下文。

更新 3

接受ildjam 的回答,因为它解决了最初的问题。我需要更多地考虑如何处理纯虚拟运算符()。同时,如果您注释掉下面的代码#define USE_VARIADICS并运行硬编码版本,则可以正常工作。如果我无法解决此问题,我将发布一个单独的问题。

代码

#include <typeinfo>
#include <functional>
#include <stdexcept>
#include <cassert>
#include <map>
#include <array>
#include <iostream>

#define USE_VARIADICS
#ifdef USE_VARIADICS
template<typename P,typename R,typename... Cs>
struct Parent_Functor_Wrapper
{
        using cb_func = std::function<R(P const&, P const& )>;

        virtual R operator()( P const&, P const& ) = 0;
};

// parent class, return type, concrete classes...
template<typename P,typename R,typename I,typename... Cs>
struct Functor_Wrapper :
        public Parent_Functor_Wrapper<P,R,Cs...>
{
        using cb_func = std::function<R(I const&, Cs const& ...)>;
        cb_func  m_cb;

        // dynamic_cast<typename... const& Cs>( u... ) -> dynamic_cast<Cs const&>(u)...
        Functor_Wrapper( cb_func cb ) : m_cb( cb ) { }
        virtual R operator()( P const& t, Cs const& ... u ) override
        {
                return m_cb( dynamic_cast<I const&>( t ), 
                        dynamic_cast<Cs const&>( u )...);
        }
};
#else
template<typename P,typename R>
struct Parent_Functor_Wrapper
{
        using cb_func = std::function<R(P const&, P const& )>;

        virtual R operator()( P const&, P const& ) = 0;
};

template<typename P,typename R,typename T,typename U>
struct Functor_Wrapper :
        public Parent_Functor_Wrapper<P,R>
{
        using cb_func = std::function<R(T const&, U const&)>;
        cb_func  m_cb;

        Functor_Wrapper( cb_func cb ) : m_cb( cb ) { }
        virtual R operator()( P const& t, P const& u ) override
        {
                return m_cb( dynamic_cast<T const&>( t ), dynamic_cast<U const&>( u ));
        }
};
#endif

template<typename T,unsigned N>
struct n_dimension
{
        using type = typename n_dimension<T,N-1>::type;
};

template<typename T>
struct n_dimension<T,1>
{
        using type = std::tuple<T>;
};

template<typename K>
K gen_key( K* p=nullptr, size_t idx=0 )
{
        return *p;
};

template<typename K,typename T,typename... Ts>
K gen_key( K* p=nullptr, size_t idx=0 )
{
        K m_instance;
        if ( p==nullptr )
                p = &m_instance;
        *(p->begin() + idx) = typeid( T ).hash_code();
        gen_key<K,Ts...>( p, ++idx );
        return m_instance;
};

template<typename F,typename P,typename... Cs>
struct multiple_dispatcher { multiple_dispatcher() { } };

template<typename F,typename P,typename I,typename... Cs>
struct multiple_dispatcher<F,P,I,Cs...>
{
        using functor_type = Parent_Functor_Wrapper<P,std::string>;
        using key_type     = std::array<size_t,F::n_dimension::val>;
        using map_type     = std::map<key_type,functor_type*>;
        using value_type   = typename map_type::value_type;

        map_type   m_jump_table;

        multiple_dispatcher( std::initializer_list<value_type> const& cb_mapping )
        {
                for( const auto& p : cb_mapping )
                        m_jump_table.insert( p );
        }

        template< typename T, typename U >
        typename F::return_type operator()( T& x, U& y )
        {
                auto k = key_type{ { x.get_id(), y.get_id() } };
                auto func = m_jump_table.at( k );
                return (*func)( x, y );
        }

        size_t size() const { return m_jump_table.size(); }
};

// =============================================================================

struct A { virtual ~A() { } 
        virtual size_t get_id() const { return typeid( A ).hash_code(); }
};
struct B : public A { virtual ~B() { } 
        virtual size_t get_id() const override { return typeid( B ).hash_code(); }
};
struct C : public A { int x; virtual ~C() { } 
        virtual size_t get_id() const override { return typeid( C ).hash_code(); }
};

struct Functor_Pairs
{
        using return_type = std::string;
        enum n_dimension { val = 2 };

  static std::string MyFn(A const& arg1, A const& arg2) { return "A,A"; }
  static std::string MyFn(A const& arg1, B const& arg2) { return "A,B"; }
  static std::string MyFn(A const& arg1, C const& arg2) { return "A,C"; }
  static std::string MyFn(B const& arg1, A const& arg2) { return "B,A"; }
  static std::string MyFn(B const& arg1, B const& arg2) { return "B,B"; }
  static std::string MyFn(B const& arg1, C const& arg2) { return "B,C"; }
  static std::string MyFn(C const& arg1, A const& arg2) { return "C,A"; }
  static std::string MyFn(C const& arg1, B const& arg2) { return "C,B"; }
  static std::string MyFn(C const& arg1, C const& arg2) { return "C,C"; }
};

// =============================================================================

std::string (*MyFun_aa)(A const&, A const&) = &Functor_Pairs::MyFn;
std::string (*MyFun_ab)(A const&, B const&) = &Functor_Pairs::MyFn;
std::string (*MyFun_ac)(A const&, C const&) = &Functor_Pairs::MyFn;
std::string (*MyFun_ba)(B const&, A const&) = &Functor_Pairs::MyFn;
std::string (*MyFun_bb)(B const&, B const&) = &Functor_Pairs::MyFn;
std::string (*MyFun_bc)(B const&, C const&) = &Functor_Pairs::MyFn;
std::string (*MyFun_ca)(C const&, A const&) = &Functor_Pairs::MyFn;
std::string (*MyFun_cb)(C const&, B const&) = &Functor_Pairs::MyFn;
std::string (*MyFun_cc)(C const&, C const&) = &Functor_Pairs::MyFn;

Functor_Wrapper<A,std::string,A,A>   w_aa( MyFun_aa );
Functor_Wrapper<A,std::string,A,B>   w_ab( MyFun_ab );
Functor_Wrapper<A,std::string,A,C>   w_ac( MyFun_ac );
Functor_Wrapper<A,std::string,B,A>   w_ba( MyFun_ba );
Functor_Wrapper<A,std::string,B,B>   w_bb( MyFun_bb );
Functor_Wrapper<A,std::string,B,C>   w_bc( MyFun_bc );
Functor_Wrapper<A,std::string,C,A>   w_ca( MyFun_ca );
Functor_Wrapper<A,std::string,C,B>   w_cb( MyFun_cb );
Functor_Wrapper<A,std::string,C,C>   w_cc( MyFun_cc );

// =============================================================================

int main( int argc, char* argv[] )
{
        B  b;
        C  c;

        A& arg1 = b;
        A& arg2 = c;

        using md_type = multiple_dispatcher<Functor_Pairs,A,B,C>;
        using K       = md_type::key_type;

        md_type  md
        {
                std::make_pair( gen_key<K,A,A>(), &w_aa ),
                std::make_pair( gen_key<K,A,B>(), &w_ab ),
                std::make_pair( gen_key<K,A,C>(), &w_ac ),
                std::make_pair( gen_key<K,B,A>(), &w_ba ),
                std::make_pair( gen_key<K,B,B>(), &w_bb ),
                std::make_pair( gen_key<K,B,C>(), &w_bc ),
                std::make_pair( gen_key<K,C,A>(), &w_ca ),
                std::make_pair( gen_key<K,C,B>(), &w_cb ),
                std::make_pair( gen_key<K,C,C>(), &w_cc )
        };

        std::cerr << "N = " << md.size() << std::endl;
        std::cerr << "RESULT = " << md( arg1, arg2 ) << std::endl;

        assert( !std::string( "B,C" ).compare( md( arg1, arg2 )) );

#if 0
        std::cerr << typeid( A ).hash_code() << std::endl;
        std::cerr << typeid( B ).hash_code() << std::endl;
        std::cerr << typeid( C ).hash_code() << std::endl;
#endif

        return 0;
}
4

1 回答 1

2

你需要改变:

dynamic_cast<typename... const& Cs>( u... )

到:

dynamic_cast<Cs const&>( u )...

前者(除了无效的语法)试图扩展Cs为单个dynamic_cast,而后者将每种类型扩展Cs为自己的dynamic_cast.

话虽如此,我不认为你override会工作,因为你的基地的operator()签名是R operator()( P const&, P const& ),而你的派生的签名不是(除非Cs const&...巧合地扩展成P const&)......

于 2013-02-22T02:04:50.830 回答