在 C# 4.0 中,您可以使用“动态”关键字作为直到运行时才知道的类型的占位符。在某些极端情况下,这是非常有用的行为。是否可以在 C++ 中模拟类似的东西,可能使用 C++0x 功能或 RTTI?
6 回答
并不真地。您可以获得的最接近的是 a void *
,但您仍然需要将其转换为适当的类型才能使用它。
更新:
基本上,试图构建一个可以编译为 C++ 的鸭式 DSL。
你至少可以通过两种方式来解决这个问题:
基于联合的变体
struct MyType {
enum { NUMBER, STRING /* etc */ } type;
union {
double number;
string str;
};
};
多态类层次结构
class MyType {
public:
/* define pure virtual operations common to all types */
};
class MyNumber : public MyType {
private:
double number;
public:
/* implement operations for this type */
};
C# 的dynamic
功能高度依赖于 .NET 的内置反射功能。由于标准 C++ 几乎不提供反射支持,因此您无法获得类似的行为。RTTI 将允许您安全地向下转换指针,但仅此而已。您距离枚举字段和方法并动态调用它们还有很长的路要走。
正如其他人已经说过的那样,这在一般情况下是不可能的,但我认为看看为什么不这样做会很有帮助。
问题有两个层次,句法层次和语义层次。
在句法级别上,您有以下代码:
dynamic d = /* something */;
d.Foo(bar); // Foo is unknown at compile time
在 .NETdynamic
中是一个编译器功能,它所做的不是生成函数调用,而是创建一个调用站点,其中包含函数名称和参数类型(用于重载)。这意味着如果你想支持动态,你必须修改编译器。确实,模板元编程允许做类似的事情,但 TMP 本质上是在编译时完成的,因此不能胜任支持运行时调用的工作。
如果您对语法不熟悉,那么您可以支持以下内容:
dynamic d = /* something */;
d.invoke("Foo", bar);
在语义层面
正如@Trillian(酷用户名BTW)所说,动态依赖于反射,这并不完全正确,您可以指定如何dynamic
实现,并且CLR类型的默认值是反射,因此绑定到的类型dynamic
变量必须支持某种运行时检查(例如 COM 的IDispatch
)。这不适用于 C++ 中的一般情况,但如果您可以将支持范围缩小到仅支持(已知)检查类型的类型,您可以dynamic
在 C++ 中实现(没有上述语法)。
这是不可能的。需要在编译时知道对象大小,因此堆栈指针可以移动适当的字节数。如果您不声明类型,那么编译器将不知道大小。C# 通过使所有对象成为指针来解决这个问题。
github 上的这个示例提供了一种可能的实现,具体取决于您的功能复杂性。
template <typename X, typename Y>
auto add(X x, Y y) -> decltype(x + y) {
return x + y;
}
add(1, 2); // == 3
add(1, 2.0); // == 3.0
add(1.5, 1.5); // == 3.0
我想不出一个可能的代码路径,其中值的类型实际上一直到运行时都是未知的。即使您将两个模块链接在一起(动态地,在运行时),它们都已经编译,并且它们可以返回的类型也完全确定,并且实际上编码为库公开的符号的错位名称。
但是,您可以推迟对类型的了解,直到必须实际编译代码。在 C++0x 中,有一个auto
关键字,它从用于初始化变量的表达式中提供类型推断,而在当前的 C++ 中,您可以使用模板,如下所示:
template<typename T>
T square(const T& someArg){
return T*T;
}
编辑:根据您对问题的评论,您可能没有类型未知的情况。更有可能的是,该类型仅限于少数(预定义)类型之一。为此,您可以使用union
类型,最好使用boost::variant