【发布时间】:2012-12-26 14:51:03
【问题描述】:
目标:
我想实现类型安全的动态多态性(即函数调用的运行时分派)在不相关的类型上 - 即在执行的类型上没有共同的基类。在我看来,这是可以实现的,或者至少在理论上是合理的。我会尝试更正式地定义我的问题。
问题定义:
鉴于以下情况:
- 两个或多个不相关类型
A1, ..., An,每个都有一个名为f的方法,可能具有不同的签名,但具有相同的返回类型 @987654324 @;和 - 一个
boost::variant<A1*, ..., An*>对象v(或任何其他类型的变体)可以并且必须在任何时候假定任何这些类型的一个值;
我的目标是编写概念上等同于 v.f(arg_1, ..., arg_m); 的指令,如果 实际类型包含在v 中是Ai。如果调用参数与 each 函数Ai 的形式参数不兼容,编译器应该会引发错误。
当然我不需要拘泥于v.f(arg_1, ..., arg_m)的语法:比如call(v, f, ...)之类的也可以。
我试图在 C++ 中实现这一点,但到目前为止我还没有提出一个好的解决方案(我确实有很多不好的解决方案)。下面我澄清一下“好的解决方案”是什么意思。
约束:
好的解决方案是任何可以让我模仿v.f(...) 成语的东西,例如call_on_variant(v, f, ...);,并且满足以下约束:
- 对于必须以这种方式调用的每个函数
f(例如ENABLE_CALL_ON_VARIANT(f))或任何可以处理的不相关类型列表A1, ..., An,不需要任何类型的单独声明多态(例如ENABLE_VARIANT_CALL(A1, ..., An))在代码的其他地方,尤其是在全局范围内; - 在调用时不需要明确命名输入参数的类型(例如
call_on_variant<int, double, string>(v, f, ...))。命名 return 类型是可以的,例如call_on_variant<void>(v, f, ...)是可以接受的。
遵循一个示例,希望能阐明我的愿望和要求。
示例:
struct A1 { void f(int, double, string) { cout << "A"; } };
struct A2 { void f(int, double, string) { cout << "B"; } };
struct A3 { void f(int, double, string) { cout << "C"; } };
using V = boost::variant<A1, A2, A3>;
// Do not want anything like the following here:
// ENABLE_VARIANT_CALL(foo, <whatever>)
int main()
{
A a;
B b;
C c;
V v = &a;
call_on_variant(v, f, 42, 3.14, "hello");
// Do not want anything like the following here:
// call_on_variant<int, double, string>(v, f, 42, 3.14, "hello");
V v = &b;
call_on_variant(v, f, 42, 3.14, "hello");
V v = &c;
call_on_variant(v, f, 42, 3.14, "hello");
}
这个程序的输出应该是:ABC。
最佳(失败)尝试:
我最接近所需解决方案的是这个宏:
#define call_on_variant(R, v, f, ...) \
[&] () -> R { \
struct caller : public boost::static_visitor<void> \
{ \
template<typename T> \
R operator () (T* pObj) \
{ \
pObj->f(__VA_ARGS__); \
} \
}; \
caller c; \
return v.apply_visitor(c); \
}();
如果在本地类中只允许模板成员,那将非常有效(请参阅this question)。有没有人知道如何解决这个问题,或建议一种替代方法?
【问题讨论】:
-
听起来像是类型擦除的工作。这可以接受吗?
-
@KerrekSB:确实,我几乎尝试了我所知道的一切,但到目前为止没有成功
-
不知怎的,在我看来这是不可能的,但我很乐意看到其他情况。
-
嗯,C++ 是静态类型的,所以你不能真正决定参数的数量和类型动态...
-
@SethCarnegie:不不,继续。我现在不太确定。我可以为固定的函数签名做到这一点,但我认为这不是我们想要的。
标签: c++ c++11 runtime polymorphism boost-variant