Как избежать дублирования кода в этих функциях? - PullRequest
1 голос
/ 10 июля 2019

Я попытался создать шаблон функции, который вызывал бы функцию-член в объекте, указанном параметром шаблона, но мне не удалось.Теперь у меня есть несколько функций, которые отличаются очень незначительно:

static void resize_callback(raw_resource* ptr, int width, int height)
{
    owner* instance = static_cast<owner*>(get_owner(ptr));
    assert(instance != nullptr);
    instance->on_resize(width, height);
} 
static void focus_callback(raw_resource* ptr, bool state)
{
    owner* instance = static_cast<owner*>(get_owner(ptr));
    assert(instance != nullptr);
    instance->on_focus(state);
} 
static void other_callback(raw_resource* ptr, type1 arg1, type2 arg2, type3 arg3)
{
    owner* instance = static_cast<owner*>(get_owner(ptr));
    assert(instance != nullptr);
    instance->on_other(arg1, arg2, arg3);
} 
...

Каждая raw_resource имеет ровно одну owner, где owner - это обертка вокруг raw_resource.Обратные вызовы поступают в низкоуровневую библиотеку C, которая не знает о owner с, а только о raw_resource с, поэтому они должны принять raw_resource*, чтобы указатель на них (обратные вызовы) имел соответствующий тип,Операции в обратных вызовах должны использовать объекты owner, поэтому они извлекают их через get_owner().

Как я могу сделать из них шаблон общей функции, который бы избежал дублирования кода? Мне нужно, чтобы экземпляры этого шаблона были конвертируемыми в соответствующие указатели функций , которые будут совместимы с их текущими сигнатурами, чтобы их можно было передавать в низкоуровневую библиотеку C.

Ответы [ 2 ]

5 голосов
/ 10 июля 2019

Вы можете использовать пакет параметров:

template <typename Func, typename... Types>
static void callback(raw_resource* ptr, Func func, Types... args)
{
    owner* instance = static_cast<window*>(get_owner(ptr));
    assert(instance != nullptr);
    (instance->*func)(args...);
}

Возможно, вы захотите передать Types по-другому.

Используется как:

callback(someptr, &owner::on_resize, width, height);

Если у вас есть C ++ 17, вы можете использовать std::invoke вместо синтаксиса ->*.

2 голосов
/ 10 июля 2019

Поскольку количество аргументов в каждом вызове функции-члена отличается, вы можете использовать следующий подход

#include <iostream>

struct A
{
    static void swap( int *x, int *y )
    { 
        int tmp = *x;
        *x = *y;
        *y = tmp;
    }

    void set( bool b )
    {
        this->b = b;
    }

    bool b;
};

template <typename ...Args>
void operation( A *ptr, Args ... args )
{
    if constexpr( sizeof...( args ) == 1 )
    {
        ptr->set( args... );
    }
    else if constexpr( sizeof...( args ) == 2 )
    {
        ptr->swap( args... );
    }            
}

int main()
{
    A a = { false };

    operation( &a, true );

    std::cout << "a.b = " << a.b << '\n';

    int x = 10; int y = 20;

    std::cout << "x = " << x << ", y = " << y << '\n';

    operation( &a, &x, &y );

    std::cout << "x = " << x << ", y = " << y << '\n';
}    

Вывод программы

a.b = 1
x = 10, y = 20
x = 20, y = 10
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...