我有一个适用于 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;
}