move-"cериализация" шаблонных параметров
От: tapatoon  
Дата: 12.03.23 11:20
Оценка:

Есть библиотека (service). Клиенты реализуют колбэк-интерфейс передачи данных (handler). Параметры для передачи передаются библиотеке, которая дёргает колбэк-интерфейс.

Хочется такой интерфейс сервиса библиотеки:
service::send(T&&... args);


И такой интерфейс колбэка (реализуется клиентом)
handler::on_send(T&&... args);


  Ничего, кроме конверта в void* не придумал

//////////////////////////////////////////////
// Код библиотеки

struct Params
{
    template<typename... Args>
    std::tuple< Args... >* Get()
    {
        return reinterpret_cast< std::tuple< Args... >* >( p );
    };

    void* p;
};

struct AbstractHandler
{
    virtual ~AbstractHandler() {}
    virtual void func( Params& ) = 0;
};

template < typename ResultT, typename... Args >
struct Function
{
    using type = std::function< ResultT( Args... ) >;
};

template< typename T >
struct HandlerBase : AbstractHandler
{
    typename Function< void, Params& >::type userFuncCaller;

    template< typename userFuncResultT, typename... userFuncArgs >
    HandlerBase( std::function< userFuncResultT( T*, userFuncArgs... )> userFunc )
    {
        userFuncCaller = [ this, userFunc ]( Params& p ){
            std::tuple< userFuncArgs... > args;
            if( p.p )
            {
                args = *p.Get< userFuncArgs... >();
                std::apply( [ this, userFunc ]( auto &&... args ) { userFunc( reinterpret_cast< T* >( this ), args... ); }, args );
            }
        };
    }

    void func( Params& p ) override
    {
        userFuncCaller( p );
    }
};

struct Caller
{
    Caller()
    {
        handler.reset( new UserHandler() );
    }

    template< typename... Args >
    void CallFunc( Args&&... args )
    {
        Params params;
        params.p = new std::tuple< Args... >( std::move( args... ) );

        handler->func( params );
    }

    std::unique_ptr< AbstractHandler > handler;
};

//////////////////////////////////////////////
// Клиентский код

struct UserHandler : HandlerBase< UserHandler >
{
    // необходимость таким образом передавать функцию удручает
    UserHandler() : HandlerBase< UserHandler >( std::function< void( UserHandler*, int ) >( &UserHandler::userFunc ) )
    {}

    void userFunc( int i )
    {
        BOOST_TEST_MESSAGE( Format( L"IN USER FUNC - %1%"_sv, i ) );
        return;
    }
};

void main()
{
    Caller call;
    call.CallFunc( 5 );
}


Будут ещё мнения как это сделать?
Спасибо
Центр ИПсО Сил Специальных Операций
Отредактировано 12.03.2023 12:02 tapatoon . Предыдущая версия . Еще …
Отредактировано 12.03.2023 12:01 tapatoon . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.