开发者

Optional structural typing possibility in C++ or any other language?

In C++ how to tell compiler that Ogre::Vector3 IS_SAME_AS SomeOtherLIB::Vector3 ? I feel that.. in languages like c++ which are not structural typed but th开发者_Go百科ere are cases when it makes sense.

Normally as game developer when working with 4+ libraries that provide sort or their own Vector3 implementation. The code is littered with ToOgre, ToThis, ToThat conversion function. Thats a lot of Float3 copying around which should not happen on first place.

Is in C++ or any other languages where we dont have to convert (copying) from one type to another which is essentially the samething. But any solution in C++ as most of the good gamedevs libs are for c/c++.


If you use templates you can define functions that take any type of argument as long as the necessary operations are defined on that type. Example:

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;
}


While it doesn't suit any situation, templates can give you "compile-time duck typing".

Lets say you have two vector types:

struct Vec3A {
    float x, y, z;
};

struct Vec3B {
    float p[3];
};

You can define function templates that hide the implementation how of to get the components:

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]; }
// ...

With such helpers you can now write generic functions that work on both:

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));
}

You can also continue by specializing utilities like length() for performance or other reasons, e.g. if a certain vector already has a member function providing you with the length:

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


If you are really sure in case of non-virtual structures, you can do a reinterpret_cast. However, it's better to:

  1. do templated wrapper functions as shown by sepp2k
  2. inherit from one of the vectors and add a conversion operator to the other vector
  3. add a separate _cast function that does the conversion


Haxe is a highly portable language with completely optional structural subtyping:

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));
    }
}

Not only is Vector3 an already usable structure, it also acts as a structural interface for other classes. Such typedef'd structs can specify function signatures as well as fields.

Haxe also has a CFFI for talking to C++ (although it still requires conversion methods), and bindings already exist for a few C++ game engines, as well as a variety of lower-level frameworks. Cross-platform engines written in pure Haxe are also being developed, targeting variously C++, Flash, and JS (both Canvas and WebGL).

This is probably not the solution you are looking for right now, but may become more interesting within a few years.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜