Функции преобразования, не являющиеся членами; Отливки различных типов, например. Вектор DirectX для вектора OpenGL

В настоящее время я работаю над игровым движком, который должен перемещать значения между движком 3D, физическим движком и языком сценариев. Поскольку мне очень часто нужно применять векторы из физического движка к 3D-объектам и вы хотите иметь возможность управлять как трехмерным, так и физическим объектом через систему сценариев, мне нужен механизм для преобразования вектора одного типа (например, vector3d<float>) к вектору другого типа (например, btVector3). К сожалению, я не могу сделать никаких предположений о том, как выкладываются классы/структуры, поэтому простой reinterpret_cast, вероятно, не будет делать.

Итак, вопрос: есть ли какой-то метод статического/не-членного литья для достижения в основном этого:

vector3d<float> operator vector3d<float>(btVector3 vector) {
    // convert and return
}

btVector3 operator btVector3(vector3d<float> vector) {
    // convert and return
}

В настоящий момент это не будет компилироваться, так как операторы-литейщики должны быть элементами-членами. (error C2801: 'operator foo' must be a non-static member)

Ответ 1

Я бы предложил написать их как пару свободных функций (т.е. не беспокоиться о том, чтобы сделать их "операторами" ):

vector3d<float> vector3dFromBt(const btVector3& src) {
    // convert and return
}

btVector3 btVectorFrom3d(const vector3d<float>& src) {
    // convert and return
}

void f(void)
{
  vector3d<float> one;   
// ...populate...   
  btVector3 two(btVectorFrom3d(one));    
// ...
  vector3d<float> three(vector3dFromBt(two));
}

Ответ 2

Вы также можете использовать шаблонный класс-оболочку, например:

template<class V>
class vector_cast {};

template<>
class vector_cast<vector3d> {
  const vector3d& v;

public:

  vector_cast(const vector3d& v) : v(v) {};

  operator vector3d () const {
    return vector3d(v);
  }

  operator btVector3 () const {
    // convert and return
  }
};

template<>
class vector_cast<btVector3> {
  const btVector3& v;

public:

  vector_cast(const btVector3& v) : v(v) {};

  operator btVector3 () const {
    return btVector3(v);
  }

  operator vector3d () const {
    // convert and return
  }
};

Использование:

void set_origin(btVector3 v);

// in your code:

vector3d v;
// do some fancy computations
set_origin(vector_cast(v));

// --- OR the other way round --- //

void set_velocity(vector3d v);

// in your code:

btVector3 v;
// do some other computations
set_velocity(vector_cast(v));

Ответ 3

Ваше выражение в вопросе верное. Оператор преобразования типов должен быть нестационарным членом. Если вам действительно нужна семантика типа преобразования, вы можете расширить каждый из этих классов для использования в вашем коде приложения:

// header:
class ConvertibleVector3d;

ConvertibleBtVector : public btVector3
{
  operator ConvertibleVector3d() const;
}

ConvertibleVector3d : public vector3d<float>
{
  operator ConvertibleBtVector() const;
}

//impl:
ConvertibleBtVector::operator ConvertibleVector3d() const
  {
    ConvertibleVector3d retVal;
// convert this into retVal...
    return retVal;
  }

ConvertibleVector3d::operator ConvertibleBtVector() const;
  {
    ConvertibleBtVector retVal;
// convert this into retVal...
    return retVal;
  }

void f(void)
{
  ConvertibleVector3d one;   
// ...populate...   
  ConvertibleBtVector two(one);    
// ...
  ConvertibleVector3d three;
  three = two;
}

Имена немного подробные, но, надеюсь, это ясно.

Общественное наследование означает, что вы должны иметь возможность использовать экземпляры этих классов так же, как базовый класс, за исключением того, что они будут назначаемыми и конструктивными друг от друга. Конечно, это объединяет два класса, но это может быть приемлемым, поскольку это звучит так, как ваше приложение намеревается сделать в любом случае.