c++ - 如何使用带有可变参数的动态转换?

标签 c++ c++11 variadic-templates

我有一个用于 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 类的一部分。为了向客户端提供通用类型/接口(interface),我有这个 Functor_Wrapper 类和采用父类类型的 operator() 。派送的时候郁闷了dynamic_cast<>将参数分解为正确的类型。

更新

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

同样适用于Functor_Wrapper中operator()的具体实现。 .

更新 2

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

更新 3

正在接受 ildjam's answer因为它解决了原来的问题。我需要更多地考虑如何处理纯虚拟 operator()。同时,如果您注释掉 #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;
}

最佳答案

你需要改变:

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

到:

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

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

话虽如此,我认为您的覆盖不会起作用,因为您的基地的operator()签名是R operator()( P const&, P const& ) 而你派生的签名不是(除非 Cs const&... 恰好扩展为 P const&)...

关于c++ - 如何使用带有可变参数的动态转换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15015538/

相关文章:

c++ - 创建没有原始键值的 HashMap

c++ - 在 C++11 中更改了默认初始化的含义?

c++ - 无法解析 cc1plus : error: unrecognized command line option "-std=c++11"

没有 root 访问权限的 linux 服务器上的 C++11 兼容编译器?

c++ - 如何: Extend C++14 template function to variadic template,参数

c++ - 如何仅使用参数包在 C++11 中实现 boost MPL FOLD ?

c++ - ldd 显示 ELF 解释器存在,但我仍然得到 "No such file or directory"

c++ - 我的与 COM 相关的代码有什么问题?

c++ - 当您希望界面拥有所有内存时,PIMPL Idiom 的替代方案

c++ - 固定大小的容器到可变参数模板参数列表的转换