【问题标题】:C++ equivalent of C# 4.0's "dynamic" keyword?C++ 相当于 C# 4.0 的“动态”关键字?
【发布时间】:2011-05-08 20:30:09
【问题描述】:

在 C# 4.0 中,您可以使用“动态”关键字作为直到运行时才知道的类型的占位符。在某些极端情况下,这是非常有用的行为。是否可以在 C++ 中模拟类似的东西,可能使用 C++0x 功能或 RTTI?

【问题讨论】:

  • 试图构建一个可以编译为 C++ 的鸭式 DSL。
  • 巧合I've written 在 C++ 中进行鸭式打字。长话短说,你没有。模板为您提供编译时的鸭子类型,但 C++ 是静态类型的。模板和多态性很接近,但通常有点难看。听起来你想要Boost.Proto
  • 你的 DSL 会支持用户定义的类型吗?

标签: c++ dynamic c++11 dynamic-typing


【解决方案1】:

这个example on 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

【讨论】:

    【解决方案2】:

    正如其他人已经说过的,这在一般情况下是不可能的,但我认为看看为什么不这样做会很有帮助。

    这个问题有两个层次,句法层次和语义层次。

    在句法层面你有以下代码:

    dynamic d = /* something */;
    d.Foo(bar); // Foo is unknown at compile time
    

    在 .NET 中,dynamic 是一个编译器功能,它所做的不是生成 函数调用,而是创建一个包含函数名称和类型的 调用站点参数(用于重载)。这意味着如果你想支持动态,你必须修改编译器。确实,模板元编程允许做类似的事情,但 TMP 本质上是在编译时完成的,因此无法胜任支持运行时调用的工作。

    如果您对语法不熟悉,那么您也许可以支持以下内容:

    dynamic d = /* something */;
    d.invoke("Foo", bar);
    

    语义层面 正如@Trillian(酷用户名BTW)所说,动态依赖于反射,这并不严格,你可以指定dynamic is implemented的方式,CLR类型的默认值是反射,所以绑定到@987654327的类型@ 变量必须支持某种运行时检查(例如 COM 的 IDispatch)。这不适用于 C++ 中的一般情况,但如果您可以将支持范围缩小到仅支持(已知)检查类型的类型,您可以在 C++ 中实现 dynamic(没有上述语法)。

    【讨论】:

      【解决方案3】:

      不是真的。您可以获得的最接近的是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 */
      };
      

      【讨论】:

      • Boost.Variant 或 Boost.Any 可以在这类事情上提供很多帮助
      【解决方案4】:

      我想不出一个可能的代码路径,其中值的类型实际上一直到运行时都是未知的。即使您将两个模块链接在一起(动态地,在运行时),它们都已经编译,并且它们可以返回的类型也已完全确定,并且实际上编码为库公开的符号的错位名称。

      但是,您可以推迟了解类型,直到必须实际编译代码。在 C++0x 中,有 auto 关键字,它从用于初始化变量的表达式中提供类型推断,而在当前的 C++ 中,您可以使用模板,如下所示:

      template<typename T>
      T square(const T& someArg){
         return T*T;
      }
      

      编辑:根据您对问题的评论,您可能没有类型未知的情况。更有可能的是,该类型仅限于少数(预定义)类型之一。为此,您可以使用union 类型,最好使用boost::variant

      【讨论】:

        【解决方案5】:

        这是不可能的。对象大小需要在编译时知道,因此堆栈指针可以移动适当的字节数。如果您不声明类型,那么编译器将不知道大小。 C# 通过使所有对象成为指针来解决这个问题。

        【讨论】:

          【解决方案6】:

          C# 的dynamic 功能高度依赖于.NET 的内置反射功能。由于标准 C++ 几乎不提供反射支持,因此您无法获得类似的行为。 RTTI 将允许您安全地向下转换指针,但仅此而已。您距离枚举字段和方法并动态调用它们还有很长的路要走。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-10-08
            • 2010-12-10
            • 1970-01-01
            • 2011-01-19
            • 1970-01-01
            • 2010-09-22
            • 2010-10-01
            • 2016-06-21
            相关资源
            最近更新 更多