我有一个有效的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<>
将参数向下转换为正确的类型。
更新
我刚才意识到我还有另一个问题:我的Parent_Functor_Wrapper
中的虚拟运算符()需要转换为P const&
的n个参数,所以我需要以某种方式展开签名!
同样适用于Functor_Wrapper
中的operator()的具体实现。
更新2
发布完整代码,以便更好地理解编程环境。
更新3
接受ildjam's answer因为它解决了原始问题。我需要更多地考虑如何处理纯虚拟运算符()。同时,如果您注释掉#define USE_VARIADICS
并运行硬编码版本,则下面的代码可以正常工作。如果我无法解决这个问题,我会发一个单独的问题。
CODE
#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;
}
答案 0 :(得分: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&
)...