reinterpret_cast<CClass*>(raw_ptr)
От: RikkiTikkiTavi Россия  
Дата: 24.08.15 12:28
Оценка:
Здраствуйте!

Хочется немного хулиганства...

В нашем продукте много точек/векторов, прямо на каждом шагу. Т.е. тройки даблов. Могут быть отдельные, могут быть массивы.
Продукт большой, разработчиков много, стандарта жёсткого нет и наличествует несколько форматов передачи данных.
С одной стороны, чаще всего встречается передача через голые указатели. С другой стороны, их надо чуток обработать и, в частности, имеется класс для работы с вектором SuperPooperVector3, который умеет все что нужно. Бинарное представление этого класса простое — 3 дабла и все.

Так вот, хочется писать примерно так:
void Foo(const double vertices[], size_t i)
{
    ...
    Vector3 v2 = AsVector3(vertices+i*3) + Vector3(1,0,0);
    ...
}

Т.е. некоторый участок памяти из 3 даблов считаем как объект класса (с совпадающем представлении в памяти) и используем его методы.
Возможная реализация преобразователя
const Vector3& AsVector3(const double* v)
{
    *reinterpret_cast<const Vector3D*>( v );
}
Vector3& AsVector3(double* v)
{
    *reinterpret_cast<Vector3D*>( v );
}


Понятно, что это некошерно. Понятно, что в общем случае это совсем зло-зло. Но если очень хочется... в отдельных случаях...

Какого будет мнение состоятельных кротов?
Re: reinterpret_cast<CClass*>(raw_ptr)
От: Went  
Дата: 24.08.15 13:06
Оценка:
Здравствуйте, RikkiTikkiTavi, Вы писали:
RTT>Какого будет мнение состоятельных кротов?
Я, как иструмент меж-коллекционного взаимодействия (то есть для всего, что можно представить как последовательную коллекцию одинаковых типов) использую std::initializer_list. То есть у математического вектора есть констуктор по std::initializer_list<double>, и функция list() возвращающая std::initializer_list<double> с его членами.
Re: reinterpret_cast<CClass*>(raw_ptr)
От: Шахтер Интернет  
Дата: 24.08.15 13:07
Оценка: +1
Здравствуйте, RikkiTikkiTavi, Вы писали:

RTT>Здраствуйте!


RTT>Хочется немного хулиганства...


RTT>В нашем продукте много точек/векторов, прямо на каждом шагу. Т.е. тройки даблов. Могут быть отдельные, могут быть массивы.


RTT>Продукт большой, разработчиков много, стандарта жёсткого нет и наличествует несколько форматов передачи данных.


Надо что-то менять в консерватории. Начать следует с руководителя проекта.
Когда проект большой и много разработчиков, то надо вводить стандарты на интерфейсы и представление данных.
Для этого делается небольшой исследовательский проект, на котором отрабатывается наиболее подходящие решения, которые потом жёстко фиксируются в основном проекте.
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re: reinterpret_cast<CClass*>(raw_ptr)
От: watchmaker  
Дата: 24.08.15 13:14
Оценка: 2 (1) +1
Здравствуйте, RikkiTikkiTavi, Вы писали:

RTT> имеется класс для работы с вектором SuperPooperVector3, который умеет все что нужно. Бинарное представление этого класса простое — 3 дабла и все.

RTT>Какого будет мнение?
Для standard-layout структур это разрешено. Даже в стандарте есть пример с reinterpret_cast и complex<T>, который, очевидно, отличается от твоего примера лишь тем, что у тебя три числа, а не два.

Хотя с массивом таких гарантий нет — то есть нельзя сначала сделать каст к указателю на массив векторов, а потом его индексировать, а нужно каждый раз делать новый каст:
Vector3* p = &AsVector3(vertices+i*3);
use(p[0]) //  можно
use(p[1]) //  нельзя

но в то же время
use(AsVector3(vertices+(i+0)*3)); //  можно 
use(AsVector3(vertices+(i+1)*3)); //  можно

Хотя практически везде будут оба варианта работать пока не встретится где-нибудь, например, агрессивное выравнивание (тогда первый код сломается, а второй гарантированно продолжит работать).




RTT> имеется класс для работы с вектором SuperPooperVector3, который умеет все что нужно


А не рассматривался вариант с классом SuperPooperVector3View, который также умеет всё что нужно, но не владеет данными, а содержит лишь содержит ссылку на первый double? Тогда такой класс можно без всяких reinterpret_cast сконструировать как из SuperPooperVector3, так и из голого массива.
Отредактировано 31.08.2015 11:12 watchmaker . Предыдущая версия . Еще …
Отредактировано 24.08.2015 13:22 watchmaker . Предыдущая версия .
Отредактировано 24.08.2015 13:18 watchmaker . Предыдущая версия .
Re: reinterpret_cast<CClass*>(raw_ptr)
От: Кодт Россия  
Дата: 24.08.15 14:32
Оценка: 2 (1)
Здравствуйте, RikkiTikkiTavi, Вы писали:

RTT>Какого будет мнение состоятельных кротов?


Ну, можно порефакторить — введя модель вектора
// прототип класса
struct SomeVector
{
  double x() const;
  double y() const;
  double z() const;
};

struct model_of_vector {}; // тэг (нужно от него наследовать)
template<class T> using bool const is_model_of_vector = std::is_base_and_derived<model_of_vector, T>::value;

определив реализации
struct VectorValue : model_of_vector
{
  double x_, y_, z_;

  double x() const { return x_; }
  double y() const { return y_; }
  double z() const { return z_; }
};

struct VectorView : model_of_vector
{
  double* xyz_;

  double x() const { return xyz_[0]; }
  double y() const { return xyz_[1]; }
  double z() const { return xyz_[2]; }
};

и сделав шаблонные функции
template<class V1, class V2>
auto operator + (V1&& v1, V2&& v2) -> typename enable_if< is_model_of_vector<V1> && is_model_of_vector<V2>, VectorValue >::type
{
  return VectorValue { v1.x() + v2.x(), v1.y() + v2.y(), v1.z() + v2.z() };
}
Перекуём баги на фичи!
Re[2]: reinterpret_cast<CClass*>(raw_ptr)
От: RikkiTikkiTavi Россия  
Дата: 31.08.15 10:21
Оценка:
W>Я, как иструмент меж-коллекционного взаимодействия (то есть для всего, что можно представить как последовательную коллекцию одинаковых типов) использую std::initializer_list. То есть у математического вектора есть констуктор по std::initializer_list<double>, и функция list() возвращающая std::initializer_list<double> с его членами.
Мы пока ограничены VS2012 и старше, но интересно
Re[2]: reinterpret_cast<CClass*>(raw_ptr)
От: RikkiTikkiTavi Россия  
Дата: 31.08.15 10:26
Оценка:
Здравствуйте, watchmaker, Вы писали:
W>Хотя с массивом таких гарантий нет — то есть нельзя сначала сделать каст к указателю на массив векторов, а потом его индексировать, а нужно каждый раз делать новый каст:
W>Vector3* p = &AsVector3(vertices+i*3);
W>use(p[0]) //  можно
W>use(p[1]) //  нельзя
W>

W>...
W>Хотя практически везде будут оба варианта работать пока не встретится где-нибудь, например, агрессивное выравнивание.
Да, с интерпретацией массива выходит явное зло, хотя я и не подразумевал пока...


RTT>> имеется класс для работы с вектором SuperPooperVector3, который умеет все что нужно

W>А не рассматривался вариант с классом SuperPooperVector3View, который также умеет всё что нужно, но не владеет данными, а содержит лишь содержит ссылку на первый double? Тогда такой класс можно без всяких reinterpret_cast сконструировать как из SuperPooperVector3, так и из голого массива.
Да, пожалуй, это будет значительно лучше
Re[2]: reinterpret_cast<CClass*>(raw_ptr)
От: RikkiTikkiTavi Россия  
Дата: 31.08.15 11:32
Оценка:
Здравствуйте, Кодт, Вы писали:

Хм, мощно!
Хотя местами не все понимаю, но в общем понятно, что очевидное решение с полиморфизмом заменяем на более эффективное.
Единственное, что функционал навязывается введением глобальных методов, а хотелось бы методы класса.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.