如何避免这些功能中的代码重复?

时间:2019-07-10 17:52:16

标签: c++ templates c++17

我尝试创建一个函数模板,该模板将在template参数指定的对象中调用成员函数,但失败了。现在,我有多个功能,它们之间的差别仅很小:

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,其中ownerraw_resource的包装。回调被馈送到一个低级C库,该库不知道owner,而只知道raw_resource,因此它们必须使用raw_resource*,即指向它们的指针(回调)具有适当的类型。回调中的操作需要使用owner对象,因此它们通过get_owner()检索它们。

如何用这些模板制作通用函数模板,从而避免代码重复? 我需要将该模板的实例化为可转换为适当的函数指针,该指针将与它们的当前签名兼容,以便可以将它们提供给低级C库。

2 个答案:

答案 0 :(得分:5)

您可以使用参数包:

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代替->*语法。

答案 1 :(得分:2)

由于每个成员函数调用中的参数数量不同,因此可以使用以下方法

#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