【问题标题】:Optional structural typing possibility in C++ or any other language?C++ 或任何其他语言中的可选结构类型的可能性?
【发布时间】:2010-06-01 21:47:38
【问题描述】:

在 C++ 中如何告诉编译器 Ogre::Vector3 IS_SAME_AS SomeOtherLIB::Vector3 ? 我觉得.. 在像 c++ 这样不是结构类型的语言中,但在某些情况下它是有意义的。

通常作为游戏开发人员使用 4 个以上提供排序的库或它们自己的 Vector3 实现。代码中到处都是 ToOgre、ToThis、ToThat 转换函数。这是很多 Float3 复制,首先不应该发生。

在 C++ 或任何其他语言中,我们不必将一种类型转换(复制)到另一种类型,这本质上是相同的。但是 C++ 中的任何解决方案,因为大多数优秀的 gamedevs 库都是针对 c/c++ 的。

【问题讨论】:

  • 我错过了什么吗?为什么用 OCaml 标记它?

标签: c++ programming-languages duck-typing structural-typing


【解决方案1】:

如果您使用模板,您可以定义接受任何类型参数的函数,只要在该类型上定义了必要的操作即可。示例:

class Foo { void quack() {} };
class Bar { void quack() {} };
class Baz {};

template<typename Duck>
void f(Duck d) {
    d.quack();
}
int main() {
    f(Foo()); // works
    f(Bar()); // works
    f(Baz()); // compile error because Baz does not have a quack method
    return 0;
}

【讨论】:

    【解决方案2】:

    虽然它不适合任何情况,但模板可以为您提供“编译时鸭子类型”

    假设您有两种矢量类型:

    struct Vec3A {
        float x, y, z;
    };
    
    struct Vec3B {
        float p[3];
    };
    

    您可以定义隐藏实现如何获取组件的功能模板:

    template<class T> float get_x(const T&);
    template<class T> float get_y(const T&);
    template<class T> float get_z(const T&);
    
    template<> float get_x<Vec3A>(const Vec3A& v) { return v.x; }
    // ...
    template<> float get_x<Vec3B>(const Vec3B& v) { return v.p[0]; }
    // ...
    

    有了这样的助手,您现在可以编写适用于两者的通用函数:

    template<class T> float length(const T& t) {
        return std::sqrt(std::pow(get_x(t), 2), 
                         std::pow(get_y(t), 2),
                         std::pow(get_z(t), 2));
    }
    

    您还可以出于性能或其他原因(例如如果某个向量已经有一个成员函数为您提供长度:

    template<> float length<Vec3C>(const Vec3C& v) {
        return v.length();
    }
    

    【讨论】:

    • “编译时鸭子类型”被称为“结构类型”,如果我没记错的话。
    • 有人知道在 Java 中这样的事情是否可行?
    【解决方案3】:

    如果你真的确定非虚拟结构的情况,你可以做一个 reinterpret_cast。但是,最好:

    1. 按照 sepp2k 所示执行模板化包装函数
    2. 从其中一个向量继承并将转换运算符添加到另一个向量
    3. 添加一个单独的 _cast 函数来进行转换

    【讨论】:

      【解决方案4】:

      Haxe 是一种高度可移植的语言,具有完全可选的结构子类型:

      typedef Vector3 = { x : double, y : double, z : double };
      
      class FancyVector3 {
          public var x : double, y : double, z : double;
      
          function dot(Vector3 v) {
              return x * v.x + y * v.y + z * v.z;
          }
      
          function length() {
              return Math.sqrt(dot(this));
          }
      }
      

      Vector3 不仅是一个已经可用的结构,它还充当其他类的结构接口。此类typedef'd 结构可以指定函数签名以及字段。

      Haxe 还有一个用于与 C++ 对话的 CFFI(尽管它仍然需要转换方法),并且已经为一些 C++ 游戏引擎以及各种低级框架提供了绑定。使用纯 Haxe 编写的跨平台引擎也在开发中,针对各种 C++、Flash 和 JS(Canvas 和 WebGL)。

      这可能不是您现在正在寻找的解决方案,但可能会在几年内变得更有趣。

      【讨论】:

        猜你喜欢
        • 2012-02-05
        • 1970-01-01
        • 2010-09-20
        • 2011-02-19
        • 2014-11-20
        • 1970-01-01
        • 2020-05-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多