我尝试创建一个函数模板,该模板将在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
,其中owner
是raw_resource
的包装。回调被馈送到一个低级C库,该库不知道owner
,而只知道raw_resource
,因此它们必须使用raw_resource*
,即指向它们的指针(回调)具有适当的类型。回调中的操作需要使用owner
对象,因此它们通过get_owner()
检索它们。
如何用这些模板制作通用函数模板,从而避免代码重复? 我需要将该模板的实例化为可转换为适当的函数指针,该指针将与它们的当前签名兼容,以便可以将它们提供给低级C库。
答案 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