【发布时间】:2017-02-09 23:33:09
【问题描述】:
考虑以下最小示例:
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。
是否有任何其他有效的替代方案来实现相同的目标,或者这是唯一可行的解决方案?
【问题讨论】:
-
我感觉到XY problem。假设您拥有所有支持模板的魔力完美运行,您能否给我们您想要编写的代码?
-
@nwp 我给了类似的东西。想象一下,有(让我说)类型的擦除数组,我想迭代它调用
s.func(s.ptr, [](auto obj){ /* ... */ });,每次使用略有不同的 lambda。我可以给你更多的细节吗?我不知道如何解释它更好。对不起。 -
数组中所有元素的共同点是什么?他们只有一个共同的成员函数
void f()吗? -
@nwp 它们是完全不相关的类型,没有共同的基础,它们提供了一组有限的成员函数,具有相同的名称并接受相同的参数。
-
是什么阻止您使用
std::vector<std::function<Retval_t(Param_t)>>并为各种类型的object填充[object](Param_t param){ return object.func(param); };?可以编写一个模板,给定一个异构对象列表将返回这样一个向量。
标签: c++ templates software-design type-erasure