考虑以下最小例子:
struct S {
using func_t = void(*)(void *);
template<typename T>
static void proto(void *ptr) {
static_cast<T*>(ptr)->f();
}
func_t func;
void *ptr;
};
struct T {
void f() {}
};
void g(S &s) {
s.func(s.ptr);
}
int main() {
T t;
S s;
s.func = &S::proto<T>;
s.ptr = &t;
g(s);
}
非常明显的想法是删除一堆对象的类型(如T
,这不是唯一可用的类型)来创建S
的实例数组,然后迭代它数组并调用预定的成员函数。
到目前为止,它很容易实现并且有效 现在我想提供一个在擦除对象上调用的外部函数,这可能是这样的:
template<typename T, typename F>
static void proto(void *ptr, F &&f) {
auto *t = static_cast<T*>(ptr);
std::forward<F>(f)(*t);
t->f();
}
或者这个:
template<typename T>
static void proto(void *ptr, void(*f)(T &)) {
auto *t = static_cast<T*>(ptr);
f(*t);
t->f();
}
被调用为:
s.func(s.ptr, [](auto obj){ /* ... */ });
一种模板方法模式,其中额外的功能由调用者而不是派生类提供 不幸的是,我无法做到这一点,因为我不能将专门化减少到可以分配给函数指针的同类。
我能看到的唯一选择是定义一个自定义类,如下所示:
struct C {
template<typename T>
void f(T &t) { /* ... */ }
// ...
};
f
以某种方式调用内部调用正确的成员函数,然后将其用作:
struct S {
using func_t = void(*)(void *, C &);
template<typename T>
static void proto(void *ptr, C &c) {
auto t = static_cast<T*>(ptr);
c.f(*t);
t->f();
}
func_t func;
void *ptr;
};
这与我使用lambda所做的相差不远,但它更冗长,需要我明确声明类C
。
是否还有其他有效的替代方法可以实现相同目标,还是唯一可行的解决方案?
答案 0 :(得分:0)
假设您可以枚举您希望支持的类型,您可以这样做:
#include <iostream>
#include <string>
#include <vector>
template <class... Ts>
struct PseudoFunction {
private:
template <class T>
static void (*function)(T &);
template <class T>
static void call_func(void *object) {
return function<T>(*static_cast<T *>(object));
}
template <class Fun>
static void assign(Fun) {}
template <class Fun, class Head, class... Tail>
static void assign(Fun fun) {
function<Head> = fun;
assign<Fun, Tail...>(fun);
}
public:
template <class T>
PseudoFunction(T *t)
: object(t)
, func(call_func<T>) {}
template <class F>
static void set_function(F f) {
assign<F, Ts...>(f);
}
void operator()() {
func(object);
}
private:
void *object;
void (*func)(void *);
};
template <class... Ts>
template <class T>
void (*PseudoFunction<Ts...>::function)(T &) = nullptr;
//example types that are not related and not copy constructible
//but have the same member function name and signature
struct T1 {
T1() = default;
T1(const T1 &) = delete;
void func(double d) {
std::cout << "T1: " + std::to_string(d) + '\n';
}
};
struct T2 {
T2() = default;
T2(const T2 &) = delete;
void func(double d) {
std::cout << "T2: " + std::to_string(d) + '\n';
}
};
int main() {
T1 t1;
T2 t2;
using PF = PseudoFunction<T1, T2>;
std::vector<PF> funcs;
funcs.push_back(&t1);
funcs.push_back(&t2);
PF::set_function([](auto &object) { object.func(3.14); });
for (auto &f : funcs) {
f();
}
}
(demo)
它具有不错的调用语法(只需要在调用对象之前指定函数)以及设置可能未使用的函数指针的一些开销。
有人可能会创建一个包装器来执行set_function
并一次性迭代PF
。