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<>、パラメーターを正しい型にダウンキャストしてダウンキャストします。

アップデート

別の問題があることに気付きました.私の仮想オペレーター()はParent_Functor_Wrappern個のパラメーターに変換するP const&必要があるため、署名を展開する必要があります!

の operator() の具体的な実装にも同じことが当てはまりますFunctor_Wrapper

更新 2

プログラミング コンテキストをよりよく理解できるように、完全なコードを投稿します。

更新 3

元の問題に対処しているため、ildjamの回答を受け入れます。純粋仮想 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;
}
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 に答える