Russian Qt Forum

Программирование => С/C++ => Тема начата: Igors от Апрель 27, 2018, 11:01



Название: оператор [] для union
Отправлено: Igors от Апрель 27, 2018, 11:01
Добрый день

Есть такая структурка
Код
C++ (Qt)
struct CData {
enum Type { type_Value, type_Coord, type_Color };
Type m_type;
union {
  double m_value;
  double m_coord[3];
  float m_color[4];
};
};
Требуется оператор [] который как минимум проверял бы индекс, напр если type_Value, то data[1] должно выбросить исключение. Ну а возврат по ссылке вообще было бы идеально. Как это сделать без унылых свитчей? Сменить union на что-то другое - пожалуйста, но сам класс CData не должен быть template

Спасибо


Название: Re: оператор [] для union
Отправлено: ViTech от Апрель 27, 2018, 11:17
std::variant.


Название: Re: оператор [] для union
Отправлено: Igors от Апрель 27, 2018, 12:15
std::variant.
Пример
Код
C++ (Qt)
void DoSomething( const CData & src, CData & dst, int index )
{
...
 
// хотелось бы записать так
dst.Set(index, src[index]);
 
// а еще лучше так
dst[index] = src[index];
}
 


Название: Re: оператор [] для union
Отправлено: ViTech от Апрель 27, 2018, 12:47
Чем не устраивает:
Код
C++ (Qt)
void DoSomething( const CData & src, CData & dst, int index)
{
   ...
   dst = src;
}

Есть  метод std::variant::index(). по нему можно проверки сделать, если надо.


Название: Re: оператор [] для union
Отправлено: Igors от Апрель 27, 2018, 15:22
Чем не устраивает:
Код
C++ (Qt)
void DoSomething( const CData & src, CData & dst, int index)
{
   ...
   dst = src;
}
Тем что это присвоит все компоненты, а нужно индексированную
Есть  метод std::variant::index(). по нему можно проверки сделать, если надо.
Это индекс текущего "типа" (а не индекса в массиве). И если делать проверки - то где "выйгрыш"? Записать то же но в стандартном стиле - ну может смысл и есть, но к теме не относится


Название: Re: оператор [] для union
Отправлено: ViTech от Апрель 27, 2018, 16:32
Так речь про индекс в массиве, хотя в union может и не массив совсем будет храниться во время выполнения программы. Интересно :).

Допустим добавите Вы оператор:
Код
C++ (Qt)
???? operator[](int index){...}
 
он какой тип возвращать должен: double или float? Как компилятор это должен определить в compile-time, если m_type хранимого значения будет известен только в run-time?

Связались с variant - кушайте свитчи. Они всё равно, в том или ином виде, будут присутствовать при работе с variant.


Название: Re: оператор [] для union
Отправлено: Авварон от Апрель 27, 2018, 16:36

он какой тип возвращать должен: double или float? Как компилятор это должен определить в compile-time, если m_type хранимого значения будет известен только в run-time?


ну? например, std::any


Название: Re: оператор [] для union
Отправлено: ViTech от Апрель 27, 2018, 16:44
ну? например, std::any

Действительно. Теперь всё пойдёт как по маслу :).


Название: Re: оператор [] для union
Отправлено: Igors от Апрель 28, 2018, 11:30
он какой тип возвращать должен: double или float?
Такие вопросы удивляют :). Ну конечно double (старший). Никаких сверхзадач типа "хранить и оперировать со всем на свете" не ставится, речь идет о конкретном, узком наборе типов перечисленном в стартовом посте.

ну? например, std::any
Баранки гну. На хрена он мне сдался, тот any чтобы потом разбираться что в нем сидит. Я хочу удобно (и с контролем) читать/писать эл-т массива, а для какого типа - отвечает вызывающий.   


Название: Re: оператор [] для union
Отправлено: ViTech от Апрель 28, 2018, 13:46
Такие вопросы удивляют :). Ну конечно double (старший). Никаких сверхзадач типа "хранить и оперировать со всем на свете" не ставится, речь идет о конкретном, узком наборе типов перечисленном в стартовом посте.

Вот значит что у Вас удивление вызывает :). В стартовом посте Вы хотели, чтобы в идеале возврат был по ссылке, значит и 'float &' можно возвращать как 'double &'? И чем не устраивает  унылый свитч для конкретного узкого набора типов?

Баранки гну. На хрена он мне сдался, тот any чтобы потом разбираться что в нем сидит. Я хочу удобно (и с контролем) читать/писать эл-т массива, а для какого типа - отвечает вызывающий.   

Т.е. когда Вы решили использовать variant, такое же возмущение Вас не охватило :)? И с variant получается "удобно (и с контролем) читать/писать эл-т массива"?


Название: Re: оператор [] для union
Отправлено: m_ax от Апрель 28, 2018, 16:40
Как уже предлогали, здесь напрашивается variant, а в качестве свича использовать визитёра:

Код
C++ (Qt)
#include <iostream>
#include <array>
#include <exception>
#include <variant.hpp>
 
typedef double value_t;
typedef std::array<double, 3> coord_t;
typedef std::array<float, 4> color_t;
typedef boost::variant<value_t, coord_t, color_t> data_t;
 
 
class my_visitor : public boost::static_visitor<value_t>
{
public:
   my_visitor(size_t index)
       : m_index(index)
   {}
 
   value_t operator()(const value_t & x) const
   {
       if (m_index != 0) throw std::out_of_range("out of range!");
 
       return x;
   }
 
   template <class T>
   value_t operator()(const T & x) const
   {
       return x.at(m_index);
   }
 
private:
   size_t m_index;
};
 
 
struct CData
{
   data_t data;
 
   value_t operator[] (size_t index) const
   {
       return boost::apply_visitor(my_visitor(index), data);
   }
};
 
int main()
{
   CData data1;
   CData data2;
 
   data1.data = 3.14;
 
   data2.data = color_t{.5f, .5f, .5f, .0f};
 
   try {
 
       std::cout << data1[0] << std::endl;
 
       std::cout <<data2[3] << std::endl;
 
   } catch (const std::out_of_range & exc)
   {
       std::cout << exc.what() << std::endl;
   }
 
   return 0;
}
 
 

Да, кстатии, такой же финт можно реализовать не только с variant, но и, например, с boost::any. Эта идея уже обсуждалась ранее здесь: http://www.prog.org.ru/topic_29268_0.html (http://www.prog.org.ru/topic_29268_0.html)
Всё, примерно аналогично:
Код
C++ (Qt)
#include <iostream>
#include <array>
#include <exception>
#include <boost/any.hpp>
#include <specmath/any_visitor/any_visitor.h>
 
typedef double value_t;
typedef std::array<double, 3> coord_t;
typedef std::array<float, 4> color_t;
 
class my_any_visitor : public any_visitor<value_t, type_list<value_t, coord_t, color_t>>
{
public:
   my_any_visitor(size_t index)
       : m_index(index)
   {}
 
   value_t operator()(const value_t & x) const
   {
       if (m_index != 0) throw std::out_of_range("out of range!");
       return x;
   }
 
   template <class T>
   value_t operator()(const T & x) const
   {
       return x.at(m_index);
   }
 
private:
   size_t m_index;
};
 
 
struct CData
{
 
   boost::any data;
 
   value_t operator[] (size_t index) const
   {
       return apply_any_visitor(my_any_visitor(index), data);
   }
};
 
int main()
{
   CData data1;
   CData data2;
 
   data1.data = 3.14;
 
   data2.data = color_t{.5f, .5f, .5f, .0f};
 
   try {
 
       std::cout << data1[0] << std::endl;
 
       std::cout << data2[1] << std::endl;
 
   } catch (const std::out_of_range & exc)
   {
       std::cout << exc.what() << std::endl;
   }
 
}
 


Приаттачу на всякий случай более свежие исходники any_visitor.h
Меташаблонная магия рулит  ;)


Название: Re: оператор [] для union
Отправлено: Igors от Май 01, 2018, 16:32
значит и 'float &' можно возвращать как 'double &'?
Кстати - можно, неск лет назад тут человек показывал, но у меня все не укладывается в голове  :)
И чем не устраивает  унылый свитч для конкретного узкого набора типов?
Да собсно всем устраивает. Вот "цена вопроса"
Код
C++ (Qt)
double CData::GetNth( size_t index ) const
{
 Q_ASSERT(index < size());
 
 switch (m_type) {
 
  case type_Value:
    Q_ASSERT(index == 0);
    return m_value;
 
   case type_Coord:
    return m_coord[index];
 
   case type_Color:
    return m_color[index];
 
   default:
     Q_ASSERT(0);
 }
 return 0.0;
}
Ну и SetNth в том же духе. Пока не уверен нужен ли оператор []. "Чем не устраивает" - ну выглядит уж очень старенько, а на дворе уже 21-й век.  Может есть какие "фишки", поспрашиваю у молодых...

Как уже предлогали, здесь напрашивается variant, а в качестве свича использовать визитёра:
...
Меташаблонная магия рулит  ;)
Ну вообще-то это класс типа QVector3D, т.е. для интенсивнейшего возврата по значению. В связи с этим вопрос - а сколько памяти сожрет такой boost::variant и сколько у него malloc'ов ?

А так.. ну да, понятно с визитером, но нет легкости, во все надо вникать, напрягаться... А стоит ли? Ведь конечный полезный эффект не так уж велик (если вообще имеется)


Название: Re: оператор [] для union
Отправлено: ViTech от Май 02, 2018, 11:47
значит и 'float &' можно возвращать как 'double &'?
Кстати - можно, неск лет назад тут человек показывал, но у меня все не укладывается в голове  :)
Что-то сомнительно для нешаблонной функции. Всё равно это костыль, достаточно дождаться какого-нибудь int среди double/float в варианте.

Ну и SetNth в том же духе. Пока не уверен нужен ли оператор []. "Чем не устраивает" - ну выглядит уж очень старенько, а на дворе уже 21-й век.  Может есть какие "фишки", поспрашиваю у молодых...
Нормально выглядит, если это надо один раз для конкретного узкого набора типов.

Ну вообще-то это класс типа QVector3D, т.е. для интенсивнейшего возврата по значению. В связи с этим вопрос - а сколько памяти сожрет такой boost::variant и сколько у него malloc'ов ?

А так.. ну да, понятно с визитером, но нет легкости, во все надо вникать, напрягаться... А стоит ли? Ведь конечный полезный эффект не так уж велик (если вообще имеется)

Если нормально визитёра написать, то никакого оверхеда быть не должно. В конечном итоге, применение визитёра к варианту развернётся примерно в тот же свитч, что Вы руками написали. Только в свитче выбор определяется по индексу типа (Type), а в визитёре по типу данных (double, double[3], float[4]). Плюс визитёра в том, что его можно применять для разных вариантов, и не нужно для каждого похожий свитч писать.


Название: Re: оператор [] для union
Отправлено: Igors от Май 02, 2018, 15:29
Задаю простой, естественный вопрос, типа "сколько весит".
Если нормально визитёра написать, то никакого оверхеда быть не должно.
Почему не вижу столь же простого ответа? Вот напр для моей допотопной структурки: 32 байта, malloc'ов нет. А тут... 

В конечном итоге, применение визитёра к варианту развернётся примерно в тот же свитч, что Вы руками написали.
Насколько я понимаю, никаких "разверток" там нет. Объявляется набор классов с базовым виртуальным методом для каждого "общего" действия. При инстанциации создаются порожденные классы для каждого темплейт типа которые зовут оте внешние огрызки кода. А при обращении зовется базовый виртуал. 

Поэтому копирование вряд ли сведется к memmove, да и хранить он будет все "инстанциированные", т.е. все 3 варианта


Название: Re: оператор [] для union
Отправлено: m_ax от Май 02, 2018, 16:04
Цитировать
Насколько я понимаю, никаких "разверток" там нет. Объявляется набор классов с базовым виртуальным методом для каждого "общего" действия.
Никаких виртуалов там нет: визитёр раскручивается в компил тайм. 

Цитировать
Задаю простой, естественный вопрос, типа "сколько весит".
Давайте померим и по производительности сравним.



Название: Re: оператор [] для union
Отправлено: ViTech от Май 02, 2018, 17:46
Задаю простой, естественный вопрос, типа "сколько весит".
Простой ответ и был дан:
В конечном итоге, применение визитёра к варианту развернётся примерно в тот же свитч, что Вы руками написали.

Вот напр для моей допотопной структурки: 32 байта, malloc'ов нет. А тут... 
Вроде ж несложно посмотреть sizeof(std::variant<double, std::array<double, 3>, std::array<float,4>>).

Насколько я понимаю, никаких "разверток" там нет. Объявляется набор классов с базовым виртуальным методом для каждого "общего" действия. При инстанциации создаются порожденные классы для каждого темплейт типа которые зовут оте внешние огрызки кода. А при обращении зовется базовый виртуал. 

Поэтому копирование вряд ли сведется к memmove, да и хранить он будет все "инстанциированные", т.е. все 3 варианта
Вы неправильно понимаете.


Название: Re: оператор [] для union
Отправлено: Igors от Май 02, 2018, 18:15
Никаких виртуалов там нет: визитёр раскручивается в компил тайм.  
Так-таки и нету? :) Ну давайте откроем исходники https://www.boost.org/doc/libs/1_53_0/boost/any.hpp (https://www.boost.org/doc/libs/1_53_0/boost/any.hpp) того же any, Вот я наблюдаю базовый класс placeholder с виртуалами, от него наследуется темплейтщина, все как обычно, другой-то дороги нет

Да и без исходников, здравый смысл никто не отменял
Код
C++ (Qt)
CData data(CData::type_Coord);
if (leftEggWants)
 data = CData(CData::type_Value);
double test = data[0];
 
Как компилятор может сгенерить "конкретный" код для присваивания? Да никак, ясно "разборка" сидит в самом операторе, а тогда нужен подскок с виртуала. Собсно это все чем рулит "магия" :)



Название: Re: оператор [] для union
Отправлено: ViTech от Май 02, 2018, 18:50
Ну давайте откроем исходники https://www.boost.org/doc/libs/1_53_0/boost/any.hpp (https://www.boost.org/doc/libs/1_53_0/boost/any.hpp) того же any,

Отрывайте исходники variant. any - это другая штука, хоть и похожая.


Название: Re: оператор [] для union
Отправлено: m_ax от Май 02, 2018, 19:13
Цитировать
Так-таки и нету?
Во-первых речь шла о визитёрах - оба варианта раскручиваются в компил тайме и там никакого полиморфизма нет.
Во-вторых по поводу variant.. Эта тема тоже уже ранее обсуждалась. Напомню, как там реализован холдер:
Код
C++ (Qt)
private:
   struct holder_base
   {
       holder_base(size_t _id) : id(_id) {}
       virtual ~holder_base() {}
       size_t id;
   };
 
   template <class T>
   struct holder : holder_base
   {
       holder(const T & _data) : holder_base(detail::type_id<T, Args...>::value), data(_data) {}
       T data;
   };
 
   std::shared_ptr<holder_base> _holder_ptr;
 


А так обеспечивается доступ к данным
Код
C++ (Qt)
template <class T>
   const T& get() const throw (std::bad_cast)
   {
       if (!is_type<T>())
           throw std::bad_cast();
 
       return std::static_pointer_cast<holder<T>>(_holder_ptr)->data;
   }
 
   template <class T>
   T& get() throw (std::bad_cast)
   {
       if (!is_type<T>())
           throw std::bad_cast();
 
       if (!_holder_ptr.unique())
           _holder_ptr = std::make_shared<holder<T>>(std::static_pointer_cast<holder<T>>(_holder_ptr)->data);
 
       return std::static_pointer_cast<holder<T>>(_holder_ptr)->data;
   }
 
   template <class T>
   variant& operator=(const T& val)
   {
       static_assert(detail::type_id<T, Args...>::value != detail::type_id<T, Args...>::bad_id, "variant::operator=(const T&): unknown type T");
 
       _holder_ptr = std::make_shared<holder<T>>(val);
       return *this;
   }
 
Да, здесь есть просадка из-за shared_pointer + make_shared - Но эта доморощенная реализация (см. аттач). Оригинальный boost::variant работает гораздо быстрее (не вникал особо, что у него там под капотом)

Цитировать
Как компилятор может сгенерить "конкретный" код для присваивания?

Я не совсем понимаю проблему? Если нужно безопасно получать и присваивать данные по индексу, то вот аналоги сеттера и геттера:
Код
C++ (Qt)
#include <iostream>
#include <array>
#include <exception>
#include <boost/variant.hpp>
 
typedef double value_t;
typedef std::array<double, 3> coord_t;
typedef std::array<float, 4> color_t;
typedef boost::variant<value_t, coord_t, color_t> data_t;
 
 
class getter_visitor : public boost::static_visitor<value_t>
{
public:
   getter_visitor(size_t index)
       : m_index(index)
   {}
 
   value_t operator()(const value_t & x) const
   {
       if (m_index != 0) throw std::out_of_range("out of range!");
 
       return x;
   }
 
   template <class T>
   value_t operator()(const T & x) const
   {
       return x.at(m_index);
   }
 
private:
   size_t m_index;
};
 
class setter_visitor : public boost::static_visitor<void>
{
public:
   setter_visitor(const value_t & data, size_t index)
       : m_data(data), m_index(index)
   {}
 
   void operator()(value_t & x) const
   {
       if (m_index != 0) throw std::out_of_range("out of range!");
 
       x = m_data;
   }
 
   template <class T>
   void operator()(T & x) const
   {
       x.at(m_index) = m_data;
   }
 
private:
   const value_t & m_data;
   size_t m_index;
};
 
 
struct CData
{
   data_t data;
 
   value_t get(size_t index) const
   {
       return boost::apply_visitor(getter_visitor(index), data);
   }
 
   void set(const value_t & x, size_t index)
   {
       boost::apply_visitor(setter_visitor(x, index), data);
   }
};
 
 
int main()
{
   CData data1;
   CData data2;
 
   data1.data = 3.14;
 
   data1.set(2.71, 0);
 
   data2.data = color_t{.5f, .5f, .5f, .0f};
 
   data2.set(5.0, 1);
 
   try {
 
       std::cout << data1.get(0) << std::endl;
 
       std::cout << data2.get(1) << std::endl;
 
   } catch (const std::out_of_range & exc)
   {
       std::cout << exc.what() << std::endl;
   }
 
   return 0;
}
 

Давайте проверим, на сколько критично этот вариант будет медленнее?


Название: Re: оператор [] для union
Отправлено: Igors от Май 03, 2018, 05:24
Давайте проверим, на сколько критично этот вариант будет медленнее?
Давайте, только не "сию минуту", подготовлю примерчик в течение 2-3 дней


Название: Re: оператор [] для union
Отправлено: Igors от Май 05, 2018, 07:41
Вот обещанный тест (аттач). Пояснения

Скорость: никто не пытается доказывать что "а велик быстрее !!!", если это компенсируется др выгодами, то есть смысл это др и юзать. Но все-таки должно быть "прилично" - напр в полтора раза медленнее, ну ладно, в два - но не на порядок же.

Удобства (использования и расширения): используется прямолинейный подход, нужен оператор - так напишем его. В моем реальном коде методов/операторов намного больше, нужна тригонометрия и.т.п. Понятно что в std есть подобное для массивов, но тогда уже не union, и хз что взамен. Да и лазание по справочнику утомляет.. Добавить пяток строчек при необходимости - мне кажется практичнее


Название: Re: оператор [] для union
Отправлено: Авварон от Май 05, 2018, 12:09
Лучше void SetNth(double value, size_t index = 0) или добавить оверлоад с 1м параметром, если хочется индекс вначале - тогда не надо будет явно передавать 0 в случае type_Value. Ваш КО.
type_Value? сириусли? enum class до вашего компилятора еще не доехал?)
Вместо size_t удобнее ssize_t, это даже стдшники признают.


Название: Re: оператор [] для union
Отправлено: ViTech от Май 05, 2018, 13:15
(https://image.ibb.co/drpfjS/sse_not_pass.jpg)

Мне одному кажется, что SSE тут циклами раскатали и свитчами разрубили?


Название: Re: оператор [] для union
Отправлено: m_ax от Май 05, 2018, 19:34
Цитировать
Вот обещанный тест (аттач).
Спасибо. Начал было пиать свой аналог Вашего CData на variantе, но когда дошёл до реализации бинарных операторов немного выпал в осадок  :)
Вот пример одного из них (из Ваших исходников):
Код
C++ (Qt)
friend CData operator * ( const CData & a, const CData & b )
{
CData dst(a);
 
for (size_t i = 0; i < dst.Size(); ++i)
dst.SetNth(i, dst.GetNth(i) * b.GetNth(i));
 
return dst;
}
 

А что произойдёт, если, например,  b.Size() < a.Size() ?  Вообще такие операции (бинарные) не корректны, как  с точки зрения здравого смысла, так и математики, если размерности объектов  не совпадают.  Или чётче формулируйте правила игры.
Какой результат мы ожидаем получить, если, например a имеет type_Color, а b type_Coord?





Название: Re: оператор [] для union
Отправлено: Old от Май 05, 2018, 21:52
Спасибо. Начал было пиать свой аналог Вашего CData на variantе, но когда дошёл до реализации бинарных операторов немного выпал в осадок  :)
Отвыкаем... выпадаем в осадок от такой ерунды "made in Igors". :)
Вот жеж "решение":
Код
C++ (Qt)
friend CData operator * ( const CData & a, const CData & b )
{
Q_ASSERT(a.Size() == b.Size());
 
CData dst(a);
 
for (size_t i = 0; i < dst.Size(); ++i)
dst.SetNth(i, dst.GetNth(i) * b.GetNth(i));
 
return dst;
}
 


А если серьезно, то потребность в таких типах уже явный признак того, что нужно все переделывать. Странно, что в CData еще нет строки, даты, матрицы и геокоординаты? Для всего из перечисленного можно описать аналогичный оператор [] :)


Название: Re: оператор [] для union
Отправлено: m_ax от Май 05, 2018, 22:32
Цитировать
А если серьезно, то потребность в таких типах уже явный признак того, что нужно все переделывать.
Согласен, здесь явный архитектурный дефект) Который продуцирует подобные костыли.. Вообще, постоянно прослеживается какая то навязчивая идея супер-классов, оправдываемая антитезисом: "ну так же проще и понятней"..  :( 


Название: Re: оператор [] для union
Отправлено: ViTech от Май 06, 2018, 10:28
Какой результат мы ожидаем получить, если, например a имеет type_Color, а b type_Coord?

Вот вы тоже удивительные вопросы задаёте. double (http://www.prog.org.ru/index.php?topic=32020.msg236146#msg236146) же :).


Название: Re: оператор [] для union
Отправлено: Igors от Май 06, 2018, 11:08
Какой результат мы ожидаем получить, если, например a имеет type_Color, а b type_Coord?
Конечно exception (пропустил assert проверку). Все операторы работают только с CData одинакового типа.

Мне одному кажется, что SSE тут циклами раскатали и свитчами разрубили?
Ну для double AVX. Немного смотрел реализацию подобного в более простом случае (просто 3 float). Геморрой безумный, где-то глючит (отключаю этот #define - все норм), а вот выигрыша не ощутил.

Согласен, здесь явный архитектурный дефект) Который продуцирует подобные костыли.. Вообще, постоянно прослеживается какая то навязчивая идея супер-классов, оправдываемая антитезисом: "ну так же проще и понятней"..  :( 
А разве не так? Примитивно? Ужасно примитивно! (я этого и не скрывал). Но что Вы можете предложить взамен кроме "фырканья" (для которого много ума не надо)? Схему с визитером? У меня стойкое впечатление что это "не тот случай" - класс выполняет слишком низкоуровневую работу, накладные расходы слишком велики. Кстати, у Вас прекрасная возможность опровергнуть это результатами тестов.  Хотя, справедливости ради, Вы единственный кто хоть что-то предложил  :)

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

Про архитектуру напишу отдельно  :)


Название: Re: оператор [] для union
Отправлено: Igors от Май 06, 2018, 11:52
Согласен, здесь явный архитектурный дефект) Который продуцирует подобные костыли..
Рискну утверждать что это не только не костыль, но такая задача является типовой.

Есть контейнеры 3 (тех же) типов
Код
C++ (Qt)
Container<double> c1;
Container<coordinate> c2;
Container<color> c3;
Которые имеют массу общего (могут рисоваться в виде графиков, отображаться в таблицах и.т.п.). Очень скоро Вы убедитесь что работать с ними в таком виде нереально. В контейнер их указатели не положить, или напр хотим (всего-навсего) читать-писать эл-т контейнера. Если сделаем напр так
Код
C++ (Qt)
template<class T>
T Container<T>::GetElement( size_t index ) const;
То теперь все что зовет этот метод тоже обязано быть "инстанциируемым темплейтом", эта зараза моментально расползется. Но подавляющая масса кода без понятия чем же "инстанциировать", поэтому сделать все темплейтами не удастся. Очевидно надо создать базовый виртуальный класс СBaseContainer и от него наследовать темплейты.  Вот и выплывает "вариантный" класс CData
Код
C++ (Qt)
CData CBaseContainer::GetElement( size_t index ) const;
void CBaseContainer::SetElement( size_t index, const CData & data );
 
И, как бы Вы не критиковали, обойтись без него не удастся (да и не нужно)  :)


Название: Re: оператор [] для union
Отправлено: ViTech от Май 06, 2018, 12:25
Ну для double AVX. Немного смотрел реализацию подобного в более простом случае (просто 3 float). Геморрой безумный, где-то глючит (отключаю этот #define - все норм), а вот выигрыша не ощутил.

И не говорите, сложно до безумия (https://godbolt.org/g/Q1vHt8).


Название: Re: оператор [] для union
Отправлено: Old от Май 06, 2018, 12:43
Рискну утверждать что это не только не костыль, но такая задача является типовой.

Есть контейнеры 3 (тех же) типов
Код
C++ (Qt)
Container<double> c1;
Container<coordinate> c2;
Container<color> c3;
Которые имеют массу общего (могут рисоваться в виде графиков, отображаться в таблицах и.т.п.).
А вот и причина. :)
Попытка бизнес-логику притянуть к Gui, чего делать категорически нельзя.


Название: Re: оператор [] для union
Отправлено: m_ax от Май 06, 2018, 13:19
К вопросу о производительности boost::variant vs union

Приаттачиваю проект с аналогом CData - MData на variantе.

Результаты такие (при numSamples = 100000 * 1024;):
Код
Bash
igors: Total time (sec) = 29
m_ax: Total time (sec) = 39
 

Выводы делайте сами)



Название: Re: оператор [] для union
Отправлено: ViTech от Май 07, 2018, 12:28
Выводы делайте сами)

boost/std::variant  - тормозное поделие? :) Зачем нужна вся эта ваша меташаблонная магия, если простой унылый свитч работает в полтора раза быстрее )).

Но если разбираться, то разница в CData и MData состоит в том, что в первом классе методы GetNth/SetNth инлайнятся, а во втором в визитёре вызывается функция и она не инлайнится. Собственно, если в CData написать:
Код
C++ (Qt)
double GetNth(size_t index) const __attribute__((noinline))
...
double SetNth(size_t index) const __attribute__((noinline))
...
то тормозить он будет также, как и MData. И если из MData выкинуть getNth/setNth и переписать операторы нормально, чтобы они работали с массивами целиком, а не поэлементно дёргали, то и скорость его приблизится к CData.

variant - универсальный класс, CData - частичная наколенная реализация. Если в CData добавить универсальность, проверки и исключения, то тормозить он будет как variant, И наоборот, для частного случая variant можно написать быструю частную версию visit/apply.

Но дело даже не в этом. Igors, Вы арифметические операторы для координат и цвета засунули в CData. Если понадобится что-то сделать с координатой или цветом, которые есть отдельно, не в CData, Вы код (а главное логику операторов) будете дублировать или как? Что мешает написать  нормальные классы координат и цвета, определить для них операции и использовать их в variant, раз уж вляпались в него? Вопрос слегка риторический, можно не отвечать :).


Название: Re: оператор [] для union
Отправлено: m_ax от Май 07, 2018, 13:50
Цитировать
Но дело даже не в этом.
Тут как ввсегда всё дело в непродуманной и кривой архитектуре.. Впрочем, ничего нового  :)


Название: Re: оператор [] для union
Отправлено: Igors от Май 08, 2018, 10:16
Зачем нужна вся эта ваша меташаблонная магия, если простой унылый свитч работает в полтора раза быстрее )).
Хоть бы и в два, такая разница не крытычна. Гораздо важнее что удается отделаться простейшими средствами - и это не ведет к громадному уродливому коду (сравните объемы реализаций). Еще важнее что для понимания нужно только знание основ языка.

Если в CData добавить универсальность
Ни в коем случае, никакому обобщению он не подлежит

Тут как ввсегда всё дело в непродуманной и кривой архитектуре..
Ну облаять велосипедиста - это святое. Я ж учил, вникал, а он.. на коленке чего-то там сбацал! Выходит я зря учил ??? Та не может такого быть!!  :)

Ладно, поговорим об архитектуре. Всегда считал (и считаю) что любой "вариант" - зло, и чем меньше он используется - тем лучше. Но увы, иногда это неизбежно, подробный пример я приводил выше - без варианта я не смогу "замкнуть" темплейты. В связи с этим возникает необходимость работать с вариантом как с единым целым. Иначе всякий раз разбираться "а что там сидит" станет невыносимым. Общие методы чем-то напоминают фабрику, но гораздо примитивнее. Напр мне нужны операторы [] и арифметики.

Так что же не так в моей архитектуре? Что же я "неправильно понимаю"? А может это Вы не улавливаете что "архитектура" и "реализация" - совершенно разные термины/понятия? Поэтому дальше будем говорить о реализации, и не употребляйте слов значение которых Вам неизвестно.

Вы арифметические операторы для координат и цвета засунули в CData. Если понадобится что-то сделать с координатой или цветом, которые есть отдельно, не в CData, Вы код (а главное логику операторов) будете дублировать или как?
Да, буду, напр у меня есть методы tan, atan, atan2 и др.

Что мешает написать  нормальные классы координат и цвета, определить для них операции и использовать их в variant, раз уж вляпались в него? Вопрос слегка риторический, можно не отвечать :).
Судя по Вашему приаттаченному коду - Вы прекрасно понимаете "что мешает" :).  Разумеется проскочить великом удается за счет повсемеcтного использования GetNth/SetNh, что, хотя и приемлемо, но не совсем хорошо (3 или 4 "мапирования" вместо одного). Попробуем мапировать напр тот же CData::оператор + (полагаем что операторы для частных случаев имеются)
Код
C++ (Qt)
CData operator + ( const CData & a, const CData & b )
{
 assert(a.m_type == b.m_type && !a.IsNull());  // видимо это надо вынести в метод
 switch (a.m_type) {
   case CData ::type_Value:
     return a.m_value + b.m_value;
 
   case CData ::type_Coord:
     return a.m_coord + b.m_coord;
 
   case CData ::type_Color:
     return a.m_color + b.m_color;
 }
 assert(0);
 return CData();
}
 
И велик быстро теряет прелесть :'( Это ж придется каждый оператор так оборачивать. Смысл всей этой возни с визитерами как раз в том что можно схлопнуть этот свитч вызовом темплейта, а здесь (насколько я понимаю) такой возможности нет. Поэтому здесь уже на десятке операторов визитер хорошо выиграет в объеме кода (хотя и не в скорости).

Однако использование визитера - удовольствие сомнительное. Ведь оборачивать каждый оператор все равно придется. А пока сообразишь что к чему приклеить.. Это сейчас задача "на слуху", а ведь часто приходится открывать чужой код без понятия что он делает. Что нам удастся почерпнуть напр их этого?
Код
C++ (Qt)
inline
Coord operator+(const Coord& a, const Coord& b)
{ return Coord{Internal::addArray(a, b)}; }
 
inline
Color operator+(const Color& a, const Color& b)
{ return Color{Internal::addArray(a, b)}; }
 
template <class E>
inline
VarData operator+(const VarData& a, const E& b)
{ return std::get<E>(a) + b; }
 
template <class E>
inline
VarData operator+(const E& a, const VarData& b)
{ return b + a; }
 
inline
VarData operator+(const VarData& a, const VarData& b)
{ return std::visit([&](const auto& b_v) { return VarData{a + b_v}; }, b); }
 
Ептель, 4 обертки для оператора +. Я понимаю что Вы хотели раскатать прием "тип от себя" (не помню как он называется), но все-таки народный свитч здесь получше  :) А то объем обертки явно превышает содержание. Неудивительно что до др операторов дело просто не дошло.


Название: Re: оператор [] для union
Отправлено: Old от Май 08, 2018, 10:24
Так что же не так в моей архитектуре? Что же я "неправильно понимаю"?
Вы пытаетесь в угоду GUI создавать абсолютно дикие и не эффективные структуры данных и работать с ними, затачивая всю бизнес-логику под эти структуры.
Хотя нужно делать ровно наоборот. Нужно придумывать структуры данных, с которыми удобно решать задачи, и подстраивать GUI под их отображение. :)


Название: Re: оператор [] для union
Отправлено: ViTech от Май 08, 2018, 10:42
Всегда считал (и считаю) что любой "вариант" - зло, и чем меньше он используется - тем лучше. Но увы, иногда это неизбежно, подробный пример я приводил выше - без варианта я не смогу "замкнуть" темплейты.

То, что Вы не можете что-то сделать, не означает, что это в принципе невозможно :).

Ептель, 4 обертки для оператора +. Я понимаю что Вы хотели раскатать прием "тип от себя" (не помню как он называется), но все-таки народный свитч здесь получше  :) А то объем обертки явно превышает содержание. Неудивительно что до др операторов дело просто не дошло.

Как говорится, наше дело предложить варианты решения задачи, Ваше - отказаться. И писать код дальше в своём стиле :).


Название: Re: оператор [] для union
Отправлено: m_ax от Май 08, 2018, 20:36
Цитировать
А может это Вы не улавливаете что "архитектура" и "реализация" - совершенно разные термины/понятия?
Да нет, я улавливаю концептуальные различия между этими понятиями) Знаете, самому приходится писать (правда, справедливости ради, нужно признать, что мои проектики в основном не долгоиграющие: написал, опубликовался и забыл).. Но я всегда стараюсь писать код, макимально расширяемым с перспективой на будущее) Вот, кстатии, на днях пришлось расширять старый проект для Phys. Rev B.) И, как уже отмечал товарищь Old - бизнес логика и взаимодействие с пользователем должны минимально знать друг о друге.. Если вообще должны.. А Вы клепаете по линейной схеме, так сказать, по пути наименьшего сопротивления, не думая о последствиях.. Ну так, во всяком случае, мне видется (имея в виду опыт Ваших постов).

Цитировать
Да, буду, напр у меня есть методы tan, atan, atan2 и др.
И как Вы собираетесь применять эти и другие функции к таким объектам, как Coord и Color? Это нормально вообще?


Название: Re: оператор [] для union
Отправлено: Igors от Май 10, 2018, 17:51
бизнес логика и взаимодействие с пользователем должны минимально знать друг о друге.. Если вообще должны.. А Вы клепаете по линейной схеме,
Этот термин "бизнес-логика" сам по себе идиотский. Нормально сказать напр так:

- есть базовые, фундаментальные структуры данных. Вот они не должны ничего знать об UI, ни одна бубочка, ни один UI-шный хедер проникнуть не должны. Однако обратное совершенно неверно, UI может знать хоть все на свете о базовых данных. Напр строка таблицы имеет доступ к контейнеру + "номер компоненты" (то что подается в Get/SetNth) чтобы отображать/редактировать значения. Это совершенно нормально и никакие принципы не нарушает.

И как Вы собираетесь применять эти и другие функции к таким объектам, как Coord и Color? Это нормально вообще?
Конечно, напр (псевдокод)
Код
C++ (Qt)
CData curr = containter.GetKeyData(index);  
CData next = containter.GetKeyData(index + 1);  
double deltaT =  containter.GetKeyTime(index + 1) - containter.GetKeyTime(index);      
container.SetSplineParam(index, SPLINE_OUT_ANGLE, (next - curr).atan2(deltaT));
Попробуйте тут влезть в разборки с конкретными типами - мало не покажется. Разумеется всегда будет что-то специфичное для каждого типа - ну так сделать все-все общим/колхозным я и не помышлял.

Как говорится, наше дело предложить варианты решения задачи, Ваше - отказаться. И писать код дальше в своём стиле :).
Ну по меньшей мере  мне стало ясно что штатное средство здесь - все-таки визитер, который вовсе не тормознутый (как я полагал). Уже результат. С обертками конечно все равно геморрой, ну "c'est la vie"


Название: Re: оператор [] для union
Отправлено: m_ax от Май 10, 2018, 18:19
Цитировать
Нормально сказать напр так:

- есть базовые, фундаментальные структуры данных. Вот они не должны ничего знать об UI, ни одна бубочка, ни один UI-шный хедер проникнуть не должны. Однако обратное совершенно неверно, UI может знать хоть все на свете о базовых данных. Напр строка таблицы имеет доступ к контейнеру + "номер компоненты" (то что подается в Get/SetNth) чтобы отображать/редактировать значения. Это совершенно нормально и никакие принципы не нарушает.
Нет, бизнес-логика это не только фундаментальные структуры данных - это ещё и их взаимодействие, их интерплей в контексте решаемой проблемы. И определение этих сущностей, которые описывают задачу и то как они должны между собой взаимодействовать, чтоб эффективно её решать и обусловлено бизнес-логикой. А сам процесс наз. проектированием)

Да, гуй взаимодействует с нашими "базовыми классами" посредством предоставляемым ими интерфейса. Но Гуй не должен диктовать, как эти структуры данных должны взаимодействовать между собой.


Название: Re: оператор [] для union
Отправлено: Old от Май 11, 2018, 07:08
это ещё и их взаимодействие, их интерплей в контексте решаемой проблемы.
Зачем вы написали столько новых "идиотских терминов". :)


Название: Re: оператор [] для union
Отправлено: Igors от Май 13, 2018, 09:53
Нет, бизнес-логика это не только ...
"..ценный мех, но и три - четыре килограмма.." и.т.д.  Данная тема не имеет никакого отношения ни к "бизнес-логике", ни к архитектуре вообще. Ну вот совершенно никакого :)  Как мы это делаем (хоть юнионом, хоть визитером, хоть как) - это чисто "реализация", с точки зрения "архитектуры" ничего не меняется - решаемая задача та же самая, мы хотим иметь общие методы для варианта в котором могут сидеть разные классы.

Также удивляет почему фаны темплейтов скептически относятся к совершенно очевидному, напрашивающемся обобщению. Стоило чуть замаскировать конкретикой (число, координата, цвет) - и это уже "кривая архитектура", мол, складывать координату с цветом - бессмыслица. Ну так мешать водку с портвейном никто и не собирался, главное - все они вектора, для них общего кода масса, а наследование не подходит. Конечно махровый темплейт, другого здесь нет.

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


Название: Re: оператор [] для union
Отправлено: ViTech от Май 13, 2018, 13:06
Также удивляет почему фаны темплейтов скептически относятся к совершенно очевидному, напрашивающемся обобщению.

Смешать всё в кучу - не значит обобщить :). В CData я вижу не обобщение, а жёсткие ограничения. В конечном итоге всё гвоздями прибито к double. Например, можете показать, как будет выглядеть CData с оператором[], если цвет будет представлен в целочисленном формате? Или цвет пришлось во float загнать в угоду этой "реализации"? Заказчик хотел цвет именно во float, и никакие другие форматы ему не нужны?


Название: Re: оператор [] для union
Отправлено: Old от Май 13, 2018, 15:50
Данная тема не имеет никакого отношения ни к "бизнес-логике", ни к архитектуре вообще.
Имеет и самое прямое.
Нет совершенно никакой необходимости в таких универсальных коллекциях, которые могут хранить числа, координаты и цвета.
Это совершенно разные типы и операции, которые к ним можно применять - разные.
Тут нужно не придумывать универсальный тип для объединения числа/координаты/цвета со странными операциями, а нормально продумать операции для каждого класса, и алгоритмы для коллекций таких типов (многие из них могут быть шаблонными).

А уж когда дойдет то визуализации таких коллекций в UI, то делать свои модели для каждой коллекции типа.


Название: Re: оператор [] для union
Отправлено: ViTech от Май 13, 2018, 17:05
Тут нужно не придумывать универсальный тип для объединения числа/координаты/цвета со странными операциями, а нормально продумать операции для каждого класса, и алгоритмы для коллекций таких типов (многие из них могут быть шаблонными).

Ну вот, вы ещё больше "идиотских терминов" понаписали :). Это всё из Букваря слова, в котором ересь одна. Слишком много "типов/коллекций/шаблонов"... Боливар не вынесет столько :). Можно же к Double Единому всё свести и дело в шляпе.


Название: Re: оператор [] для union
Отправлено: Igors от Май 14, 2018, 13:13
Смешать всё в кучу - не значит обобщить
Ну ладно, архитектура - так архитектура, все равно в изначальной постановке тема себя исчерпала. Базовые сущности

1) Имеются 3D объекты, напр (полигонная) геометрия (сфера, куб) или источник света или еще что (всего десятка полтора типов).

2) Каждый объект имеет набор параметров. При создании объекта ему назначается дефаултный набор параметров, напр для большинства объектов по меньшей мере позиция в сцене, углы поворота и масштаб. Это набор может динамически меняться, напр подключенная к объекту текстура создаст немало своих параметров.

3) Каждый параметр - анимационная кривая, контейнер ключ (время) + значение, которое может быть вектором (XYZ), цветом (ARGB), double (signed/unsigned), int (signed/unsigned) и bool. Есть текущее время (анимации), изменяемое юзером. Каждый параметр должен уметь выдавать значение (своего типа)  для заданного времени t (может совпадать с текущим но может и нет). Обычно это значение интерполированное с помощью сплайна (опции которого хранятся в каждом эл-те контейнера)

Вот собсно и все, банально и практически стандартно в любом 3D приложении. Слушаю Ваши предложения/мысли  - как организовать параметры, какие структуры данных это должны быть.


Название: Re: оператор [] для union
Отправлено: ViTech от Май 14, 2018, 13:41
Ну ладно, архитектура - так архитектура, все равно в изначальной постановке тема себя исчерпала. Базовые сущности
...
Вот собсно и все, банально и практически стандартно в любом 3D приложении. Слушаю Ваши предложения/мысли  - как организовать параметры, какие структуры данных это должны быть.

Вроде это всё обсуждали много месяцев назад в этой теме (http://www.prog.org.ru/topic_31554_0.html). Есть ли смысл повторяться? Вы же всё равно всё сделаете по своему :). Old чуть выше вкратце написал, какой должна быть архитектура. Именно это я в той теме и пытался растолковать.


Название: Re: оператор [] для union
Отправлено: Igors от Май 14, 2018, 15:35
Вроде это всё обсуждали много месяцев назад в этой теме (http://www.prog.org.ru/topic_31554_0.html). Есть ли смысл повторяться?
Помню. Правду сказать, я из этого ничего не почерпнул, все свелось к бесконечным вопросам/уточнениям пока собеседники не выдохлись :) Увы, такова судьба почти всех "архитектурных" тем, хорошо еще собеседник попался интеллигентный.   

Вы же всё равно всё сделаете по своему :).
Так других реальных предложений не видно. Об "архитектуре" калякать хорошо, а доходит до дела ... "нужно знать задачу" :) Что практически означает - делать человек ничего не хочет, ото как-то сделано - и пусть работает, а я пока книжечки почитаю, поумничаю  :) 


Название: Re: оператор [] для union
Отправлено: deMax от Май 14, 2018, 17:39
Ну ладно, архитектура - так архитектура, все равно в изначальной постановке тема себя исчерпала. Базовые сущности

Давайте начнем с простого, что хотите написать, а мы подумаем как сову на это натянуть. Может вообще часть кода на golang, java.... написать.

А вот такой вариант, чем плох:
Цитировать
templete <T> class value { T get(Time) }

class Object3D {
 value<float> x,y,z;
}


Название: Re: оператор [] для union
Отправлено: Old от Май 14, 2018, 18:09
Давайте начнем с простого, что хотите написать, а мы подумаем как сову на это натянуть.
Мы все вместе взятые вряд ли сможем сравнится в этом с автором темы. :)


Название: Re: оператор [] для union
Отправлено: ViTech от Май 14, 2018, 21:23
Так других реальных предложений не видно. Об "архитектуре" калякать хорошо, а доходит до дела ... "нужно знать задачу" :) Что практически означает - делать человек ничего не хочет, ото как-то сделано - и пусть работает, а я пока книжечки почитаю, поумничаю  :) 

Задачу нужно знать всегда. Взять хотя бы текущую тему: если знать задачу, то ни CData виде variant, ни тем более operator[] для union не нужны. Можно было бы время участников форума на что-то более полезное потратить. Например на то, как работать с контейнерами из элементов Value, Coord, Color по отдельности; в compile-time в составе структуры, tuple; в run-time в составе vector. Как для этого примеры операторов из моего VarData органично расширяются для контейнеров. Как можно std::any и его визитёров применять, чтобы в vector  в run-time добавлять различные контейнеры данных, если с проектированием голову особо ломать не хочется.


Название: Re: оператор [] для union
Отправлено: Igors от Май 15, 2018, 05:05
А вот такой вариант, чем плох:
Цитировать
templete <T> class value { T get(Time) }

class Object3D {
 value<float> x,y,z;
}
"Параметр" - вовсе не "поле данных" (объекта). Напр та же "позиция" (объекта). Казалось бы, ну она-то уж всегда существует! Это не совсем так, юзер может переключаться
Код
C++ (Qt)
value<coord> pos;  // общие ключи t (время) на 3 компоненты
...
value<float> x, y, z;  // свои ключи у каждой компоненты
Др словами параметры могут создаваться/удаляться динамически, поэтому "универсальный контейнер" придется делать так или иначе. Кстати подобная задача возникает у меня далеко не в первый раз, она вовсе не является чем-то необычным, тем более "костылем"


Название: Re: оператор [] для union
Отправлено: Авварон от Май 15, 2018, 17:34
Смешать всё в кучу - не значит обобщить
Ну ладно, архитектура - так архитектура, все равно в изначальной постановке тема себя исчерпала. Базовые сущности

1) Имеются 3D объекты, напр (полигонная) геометрия (сфера, куб) или источник света или еще что (всего десятка полтора типов).

2) Каждый объект имеет набор параметров. При создании объекта ему назначается дефаултный набор параметров, напр для большинства объектов по меньшей мере позиция в сцене, углы поворота и масштаб. Это набор может динамически меняться, напр подключенная к объекту текстура создаст немало своих параметров.

3) Каждый параметр - анимационная кривая, контейнер ключ (время) + значение, которое может быть вектором (XYZ), цветом (ARGB), double (signed/unsigned), int (signed/unsigned) и bool. Есть текущее время (анимации), изменяемое юзером. Каждый параметр должен уметь выдавать значение (своего типа)  для заданного времени t (может совпадать с текущим но может и нет). Обычно это значение интерполированное с помощью сплайна (опции которого хранятся в каждом эл-те контейнера)

Вот собсно и все, банально и практически стандартно в любом 3D приложении. Слушаю Ваши предложения/мысли  - как организовать параметры, какие структуры данных это должны быть.

Ну а собсно, чем обычный (ку)вариант-то плох? Кажется, QVariantAnimation - это почти то, что вам надо. Делаете абстрактный метод variant getValue(t), дальше конфигурируете каждый параметр своей анимацией (либо список значений, либо приближение по сплайну с опорными точками), а потом вызываете getValue для каждого параметра от текущего t.


Название: Re: оператор [] для union
Отправлено: Igors от Май 16, 2018, 13:25
Ну а собсно, чем обычный (ку)вариант-то плох? Кажется, QVariantAnimation - это почти то, что вам надо.
Никогда не интересовался этим классом. Открываю... Ой, ну что же они "смешали все в кучу" - ведь необходимости в таких универсальных коллекциях никакой! Не понял, а почему сразу стих бурный поток критики? Ну хотя бы вот
Код
C++ (Qt)
   switch(interpolationType)
   {
   case QMetaType::Int:
       return castToInterpolator(_q_interpolateVariant<int>);
   case QMetaType::UInt:
       return castToInterpolator(_q_interpolateVariant<uint>);
   case QMetaType::Double:
       return castToInterpolator(_q_interpolateVariant<double>);
   case QMetaType::Float:
       return castToInterpolator(_q_interpolateVariant<float>);
   case QMetaType::QLine:
       return castToInterpolator(_q_interpolateVariant<QLine>);
   case QMetaType::QLineF:
       return castToInterpolator(_q_interpolateVariant<QLineF>);
   case QMetaType::QPoint:
       return castToInterpolator(_q_interpolateVariant<QPoint>);
   case QMetaType::QPointF:
       return castToInterpolator(_q_interpolateVariant<QPointF>);
   case QMetaType::QSize:
       return castToInterpolator(_q_interpolateVariant<QSize>);
   case QMetaType::QSizeF:
       return castToInterpolator(_q_interpolateVariant<QSizeF>);
   case QMetaType::QRect:
       return castToInterpolator(_q_interpolateVariant<QRect>);
   case QMetaType::QRectF:
       return castToInterpolator(_q_interpolateVariant<QRectF>);
   default:
       return 0; //this type is not handled
   }
 
ViTech, ну где же Ваша брызжущая ирония? А m_ax сразу как ветром сдуло  :)

А серьезно - да, "оно", задача-то довольно типовая. Просто у меня она намного больше, и меня не интересуют универсальность и расширяемость, поэтому хранение самих данных в виде варианта в моем случае жирновато. Также они отделались только интерполяцией, у меня так не выходит, есть сплайны с контролами.

НО общение с эти классом - только через вариант (любой его аналог), тут др ходов нет 


Название: Re: оператор [] для union
Отправлено: Old от Май 16, 2018, 13:48
Не понял, а почему сразу стих бурный поток критики?
А где он стих?
Это отвратительное решение из-за отвратительной универсальности варианта.
Еще одно подтверждение того, что универсальные контейнеры, такие как вариант, зло.


Название: Re: оператор [] для union
Отправлено: Авварон от Май 16, 2018, 14:07
Никогда не интересовался этим классом. Открываю... Ой, ну что же они "смешали все в кучу" - ведь необходимости в таких универсальных коллекциях никакой! Не понял, а почему сразу стих бурный поток критики? Ну хотя бы вот
Код
C++ (Qt)
   switch(interpolationType)
   {
   case QMetaType::Int:
       return castToInterpolator(_q_interpolateVariant<int>);
   case QMetaType::UInt:
       return castToInterpolator(_q_interpolateVariant<uint>);
   case QMetaType::Double:
       return castToInterpolator(_q_interpolateVariant<double>);
   case QMetaType::Float:
       return castToInterpolator(_q_interpolateVariant<float>);
   case QMetaType::QLine:
       return castToInterpolator(_q_interpolateVariant<QLine>);
   case QMetaType::QLineF:
       return castToInterpolator(_q_interpolateVariant<QLineF>);
   case QMetaType::QPoint:
       return castToInterpolator(_q_interpolateVariant<QPoint>);
   case QMetaType::QPointF:
       return castToInterpolator(_q_interpolateVariant<QPointF>);
   case QMetaType::QSize:
       return castToInterpolator(_q_interpolateVariant<QSize>);
   case QMetaType::QSizeF:
       return castToInterpolator(_q_interpolateVariant<QSizeF>);
   case QMetaType::QRect:
       return castToInterpolator(_q_interpolateVariant<QRect>);
   case QMetaType::QRectF:
       return castToInterpolator(_q_interpolateVariant<QRectF>);
   default:
       return 0; //this type is not handled
   }
 
ViTech, ну где же Ваша брызжущая ирония? А m_ax сразу как ветром сдуло  :)

А серьезно - да, "оно", задача-то довольно типовая. Просто у меня она намного больше, и меня не интересуют универсальность и расширяемость, поэтому хранение самих данных в виде варианта в моем случае жирновато. Также они отделались только интерполяцией, у меня так не выходит, есть сплайны с контролами.

НО общение с эти классом - только через вариант (любой его аналог), тут др ходов нет  

Очевидно, что вам это не надо - у вас будет интерполятор работать с _одним_ типом, а не быть универсальным, универсальный только интерфейс передачи. Типа
Код:
ColorInerpolator : public AbstractInterpolator
{
    ColorInerpolator(CurveType t, Color c1, ...) {} // опорные параметры, тип кривой
    ColorInerpolator(std::vector<Color> &colors) {} // тупо массив точек
    Variant getValue(TimeType t) override {...} // например return this->m_colors[t];
}
А дальше
Код:
void interpolateAll(TimeType t)
{
    std::map<Key, Variant> properies;
    for (auto key: requiredKeys) {
        auto interpolator = getInterpolatorForKey(key);
        properies.insert({key, interpolator->getValue(t)});
    }
}
А юзать уже соответственно
color = properties["color"].toColor();
point = properties["point"].toPoint();


Название: Re: оператор [] для union
Отправлено: deMax от Май 16, 2018, 14:24
Есть такая структурка
Код
C++ (Qt)
struct CData {
enum Type { type_Value, type_Coord, type_Color };
Type m_type;
union {
  double m_value;
  double m_coord[3];
  float m_color[4];
};
};
Спасибо

Код:
struct CData {
 enum Type { type_Value, type_Coord, type_Color };
 Type m_type;
 union {
   double m_value;
   double m_coord[3];
   float m_color[4];
 };

 Some operator[](const int &i) {
     switch (i) {
     case 1: return Some{&this->m_value, i, sizeof (m_value)};
     case 2: return Some{&this->m_coord, i, sizeof (m_coord)};
     case 3: return Some{&this->m_color, i, sizeof (m_color)};
     }
     return Some{};
 }
};

struct Some{
    void* ptr;
    int type;
    int size;

    Some operator=(const Some& other) {
        if( this->type != other.type )
            qWarning()<<"!!!";

        memcpy(this->ptr, other.ptr, this->size);
        return *this;
    }
};
трэш конечно, но может как идея подойдет(не проеверял)
dst[1]=src[1]; должна работать


Название: Re: оператор [] для union
Отправлено: Авварон от Май 16, 2018, 14:36
А, ну да, всё, что я написал подразумевает наличиет классов "точка" "цвет" и тп, а не просто массив из 3х-4х даблов (ну хотя бы чуток обернуть эти массивы)


Название: Re: оператор [] для union
Отправлено: ViTech от Май 16, 2018, 15:41
Никогда не интересовался этим классом.
Аналогично :).

ViTech, ну где же Ваша брызжущая ирония?

Иронизировать над Qt уже грешно, ибо старенький он. И приходится ему тащить тяжкий груз обратной совместимости. И разрабатывался он во времена, когда в стандартной библиотеке С++ ещё толком ничего не было (до нашей эры/С++11), не говоря уже о возможностях самих компиляторов. И приходилось кучу костылей для него велосипедить.

Архитектурой Qt я не восторгаюсь, скорее наоборот. Хотя понимаю, почему она такая (возможности компиляторов/std на момент разработки, обратная совместимость, поддержка кучи платформ). Менять архитектуру и перепроектировать классы Qt теперь никто не будет, жить ему с этим до конца дней своих. Потому как если всё менять, то это уже и не Qt будет :).

С другой стороны, на этом этапе (http://www.prog.org.ru/topic_31554_0.html), насколько я понял, у Вас была возможность начать всё с довольно чистого листа. Когда нормальные компиляторы уже C++14 полностью поддерживали (и можно было даже на C++17 закладываться), в std больше полезного стало (можно boost не тащить), поддержка шаблонов лучше, велосипедов меньше, трава зеленее, Букварь толще, паттерны стройнее... лепота :) (хотя есть куда ещё стремиться). Так что, на мой взгляд, можно было для той задачи решение получше придумать . Посему позволяю себе иногда поиронизировать :).


Название: Re: оператор [] для union
Отправлено: Igors от Май 17, 2018, 06:38
Просьба цитированием не злоупотреблять
Очевидно, что вам это не надо - у вас будет интерполятор работать с _одним_ типом, а не быть универсальным, универсальный только интерфейс передачи. Типа
Код:
ColorInerpolator : public AbstractInterpolator
{
    ColorInerpolator(CurveType t, Color c1, ...) {} // опорные параметры, тип кривой
    ColorInerpolator(std::vector<Color> &colors) {} // тупо массив точек
    Variant getValue(TimeType t) override {...} // например return this->m_colors[t];
}
Здесь предполагается что вход интерполяции - просто TimeType t который QEasingCurve умеет посчитать. Однако для Безье-подобных кубических сплайнов это не так, там значение вычисляется
Код:
value = point0 * k0(t) + ctl0 * k1(t) + ctl1 * k2(t) + point1 * k3(t);
Где
t - время на сегменте (от 0 до 1)
point0, point1 - значения в начале и конце сегмента (напр QColor)
k(t) - интерполяционный полином (обычно Эрмит или Бернштейн)
ctl0, ctl1 - настраиваемые параметры (контрольные точки) сплайна

Вот этих настраиваемых параметров я в Qt реализации не увидел (ну может плохо смотрел). Это числа double которые юзер может менять подстраивая таким образом кривизну (собсно поэтому Безье сплайны так популярны). Числа свои для каждого "канала", напр для одного double - одно число, для координаты 3, для цвета 4. Таким образом каждый канал интерполируется независимо, хотя коэффициенты полинома одинаковы.

Ну и тут получается изрядная котовасия - просто так интерполировать "голые" значение (напр QColor) я не могу, т.к. нужно еще знать контрольные точки, но откуда их взять (где хранить)?


Название: Re: оператор [] для union
Отправлено: Igors от Май 17, 2018, 06:50
трэш конечно, но может как идея подойдет(не проеверял)
dst[1]=src[1]; должна работать
Ну как-то совсем вяло. Если трэш - то зачем пердлагать? Идея (насколько я понял) извлечь адрес и там уже темплейтом - так это никак не экономит свитчевание. И чего ж это присваивание должно работать если оператор [] возвращает по значению? Наоборот, не должно.


Название: Re: оператор [] для union
Отправлено: Igors от Май 17, 2018, 07:29
..и можно было даже на C++17 закладываться..
Я придерживаюсь совершенно противоположного мнения. Все эти новшества конечно интересны и полезны, но на архитектурные решения они практически никак не влияют.

Архитектурой Qt я не восторгаюсь
Хмм.. может не стоит так категорично? Тут наблюдается эффект о котором я читал в одной фэнтэзи (кажется "Маг в законе" но точно не помню). Смысл в чем: быть "нулевым" оказывается... хорошо :) Ну вот не знает человек дуста, а слово "сплайн" только слышал и все. И что? Берет букварь, подбирает нужный класс и через денек-другой - реальный результат. А мы (такие умные) - все чего-то спорим, сомневаемся, а ни к чему реальному пока не пришли  :)

Может попробуем с чего то начать? Как вообще должен хранить данные класс CParameter? (можно Curve, Container, называйте как хотите). Делать его "инстанциируемым темплейтом" нельзя, он сразу всех задолбает (см постановку выше). Тогда как? Qt реализует незатейливо
Код
C++ (Qt)
QVector<QPair<double, QVariant> >
 
Но мы-то знаем что вариант - зло, более того, у нас очень узкий набор типов (оглашен выше). И вообще - хорош ли тут QVector? Слушаю Ваши предложения/мысли


Название: Re: оператор [] для union
Отправлено: Авварон от Май 17, 2018, 10:36
Просьба цитированием не злоупотреблять
Здесь предполагается что вход интерполяции - просто TimeType t который QEasingCurve умеет посчитать. Однако для Безье-подобных кубических сплайнов это не так, там значение вычисляется
Код:
value = point0 * k0(t) + ctl0 * k1(t) + ctl1 * k2(t) + point1 * k3(t);
Где
t - время на сегменте (от 0 до 1)
point0, point1 - значения в начале и конце сегмента (напр QColor)
k(t) - интерполяционный полином (обычно Эрмит или Бернштейн)
ctl0, ctl1 - настраиваемые параметры (контрольные точки) сплайна

Вот этих настраиваемых параметров я в Qt реализации не увидел (ну может плохо смотрел). Это числа double которые юзер может менять подстраивая таким образом кривизну (собсно поэтому Безье сплайны так популярны). Числа свои для каждого "канала", напр для одного double - одно число, для координаты 3, для цвета 4. Таким образом каждый канал интерполируется независимо, хотя коэффициенты полинома одинаковы.

Ну и тут получается изрядная котовасия - просто так интерполировать "голые" значение (напр QColor) я не могу, т.к. нужно еще знать контрольные точки, но откуда их взять (где хранить)?

Причем тут EasingCurve, я просто показал пример. Параметры вы передаете в конструктор класса.
Или вы хотите сказать, что у вас от t меняется ctl1? т.е. value = point0 * k0(t) + ctl0(t) * k1(t) + ctl1(t) * k2(t) + point1 * k3(t); ?
Просто как я написал - да, зависит только от времени. В целом, можно всё это переделать на пачку параметров в виде мапы.


Название: Re: оператор [] для union
Отправлено: Авварон от Май 17, 2018, 10:37
..и можно было даже на C++17 закладываться..
Я придерживаюсь совершенно противоположного мнения. Все эти новшества конечно интересны и полезны, но на архитектурные решения они практически никак не влияют.


Пару страниц назад вы жаловались что говнокодите потому что union не умеет в классы. Так вот, теперь умеет:)


Название: Re: оператор [] для union
Отправлено: ViTech от Май 17, 2018, 12:37
Все эти новшества конечно интересны и полезны, но на архитектурные решения они практически никак не влияют.

Архитектурные решения и алгоритмы обычно унифицированы и не сильно зависят от языка, на котором они будут реализовываться. Зато от языка и библиотек сильно зависит, сколько велосипедов и костылей придётся написать, чтобы воплотить эту архитектуру в коде. Для меня, с каждым принятым стандартом С++, написание кода упрощается, в некоторых аспектах очень даже значительно. И Ваш CData из начального поста есть не что иное, как std::variant, появившийся в С++17. Можно не велосипедить и boost не таскать :).

Тут наблюдается эффект о котором я читал в одной фэнтэзи (кажется "Маг в законе" но точно не помню). Смысл в чем: быть "нулевым" оказывается... хорошо :) Ну вот не знает человек дуста, а слово "сплайн" только слышал и все. И что? Берет букварь, подбирает нужный класс и через денек-другой - реальный результат.

Если "нулевой" рассматривать в контексте, что у человека свежий взгляд на задачу и нет стереотипов по ней, то может и помочь. А может и нет. Если "нулевой", в смысле ничего не знает, то скорее совсем не поможет. Но сказки на то и сказки, чтобы Емеля-дурачок лежал на печи, а всё делалось "по щучьему веленью, по моему хотенью" :).

А мы (такие умные) - все чего-то спорим, сомневаемся, а ни к чему реальному пока не пришли  :)

Не мы, а Вы :). Вам же что не предложи - всё не нравится.

Свои мысли и предложения я озвучил в "той самой теме". С тех пор они не изменились.


Название: Re: оператор [] для union
Отправлено: Igors от Май 18, 2018, 08:28
Или вы хотите сказать, что у вас от t меняется ctl1?
Нет, ctl0/ctl1 задаются юзером, причем они свои (индивидуальны) для каждой компоненты, напр для x, y, z будет тройка ctl0 и тройка ctl1. Тогда юзер может крутить этот вектор интерактивно (для этого Безье сплайн и берут). А в Qt реализации, к сожалению, этого нет, кривая как бы "одномерна".

Выкрутиться можно напр так: свалить все параметры в свой вариант и сказать EasyCurve что кривая линейна, а на интерполяции все посчитать самому - на так я практически ничего не имею с готового класса.

Пару страниц назад вы жаловались что говнокодите потому что union не умеет в классы. Так вот, теперь умеет:)
Я сказал что мой код выглядит весьма старомодно и предложил сравнить его с "современным"  :). Хотя пока никаких убедительных преимуществ "модерна" не наблюдаю - все равно надо "следить за тенденциями"   

Про "юнион в классы" не понял


Название: Re: оператор [] для union
Отправлено: Igors от Май 18, 2018, 08:41
Свои мысли и предложения я озвучил в "той самой теме". С тех пор они не изменились.
В одной из наших полемик (может в той самой теме) я озвучил
Цитировать
мыслей как не было так и нет
Вижу тут тоже ничего не изменилось  :)
Не мы, а Вы :). Вам же что не предложи - всё не нравится.
Ну вот хоть убейте - НЕ ПОМНЮ ни одного Вашего предложения. Может высказанные Вами идеи слишком тонкие для меня (я спокойно к этому отношусь), но ведь как ни крути, а данные так или иначе хранить придется. Вот пару постов назад задаю вопрос как. Ответа нет, только переводы стрелок :) Ну на нет и суда нет


Название: Re: оператор [] для union
Отправлено: Авварон от Май 18, 2018, 10:03
Нет, ctl0/ctl1 задаются юзером, причем они свои (индивидуальны) для каждой компоненты, напр для x, y, z будет тройка ctl0 и тройка ctl1. Тогда юзер может крутить этот вектор интерактивно (для этого Безье сплайн и берут). А в Qt реализации, к сожалению, этого нет, кривая как бы "одномерна".

Выкрутиться можно напр так: свалить все параметры в свой вариант и сказать EasyCurve что кривая линейна, а на интерполяции все посчитать самому - на так я практически ничего не имею с готового класса.


Фейспалм.жпг.
Я не предлагаю исользовать QAnimation. Я предлагаю сделать по _аналогии_ - есть виртуальный метод интерполяции, а все параметры для интерполяции задаются в конструкторе. Юзер поменял параметр - ок, удалили старый интерполятор, создали новый. Или можно в нем геттеров-сеттеров наделать, как удобно.


Название: Re: оператор [] для union
Отправлено: ViTech от Май 18, 2018, 11:32
Ну вот хоть убейте - НЕ ПОМНЮ ни одного Вашего предложения.

Не вижу, не понимаю, не помню - тут я ничем помочь не могу. Это компетенция специалистов другой области :). Если этот пример (http://www.prog.org.ru/index.php?topic=31554.msg233458#msg233458) - не предложение, то я уже и не знаю, что можно назвать предложением :). Но это было давно, можно и забыть.

Может высказанные Вами идеи слишком тонкие для меня (я спокойно к этому отношусь), но ведь как ни крути, а данные так или иначе хранить придется. Вот пару постов назад задаю вопрос как. Ответа нет, только переводы стрелок :) Ну на нет и суда нет

Ещё ранее, чем "пару постов назад" я писал (http://www.prog.org.ru/index.php?topic=32020.msg236304#msg236304):
Цитировать
Например на то, как работать с контейнерами из элементов Value, Coord, Color по отдельности; в compile-time в составе структуры, tuple; в run-time в составе vector. Как для этого примеры операторов из моего VarData органично расширяются для контейнеров. Как можно std::any и его визитёров применять, чтобы в vector  в run-time добавлять различные контейнеры данных, если с проектированием голову особо ломать не хочется.
но да, это могло быть тонко :).

Фейспалм.жпг.
Я не предлагаю исользовать QAnimation. Я предлагаю сделать по _аналогии_ - есть виртуальный метод интерполяции, а все параметры для интерполяции задаются в конструкторе. Юзер поменял параметр - ок, удалили старый интерполятор, создали новый. Или можно в нем геттеров-сеттеров наделать, как удобно.

Про интерполятор уже что-то было (http://www.prog.org.ru/index.php?topic=31554.msg233614#msg233614). Не зашло :).


Название: Re: оператор [] для union
Отправлено: Авварон от Май 18, 2018, 13:42
Ну там никогда "не заходит"


Название: Re: оператор [] для union
Отправлено: Igors от Май 19, 2018, 10:27
Я не предлагаю исользовать QAnimation. Я предлагаю сделать по _аналогии_ - есть виртуальный метод интерполяции, а все параметры для интерполяции задаются в конструкторе. Юзер поменял параметр - ок, удалили старый интерполятор, создали новый. Или можно в нем геттеров-сеттеров наделать, как удобно.
Действуем по примеру из букваря, создали класс MyColor (4 float). Понимаем "интерполяция" буквально, т.е. взвешивание значений
Код
C++ (Qt)
QVariant myColorInterpolator(const MyColor &start, const MyColor &end, qreal progress)
{
// красная компонента
  float red = start.red * (1.0 - progress) + end.red * progress;
 
// др компоненты
   ...
   return MyColor(red, green, blue);
}
 
Пусть start = end = 0 (все компоненты нулевые), тогда на выходе получим тоже нулевой цвет при любом progress. Однако для настраиваемых сплайнов это нет так (аттач). Две нулевые точки могут интерполироваться самыми разнообразными кривыми, причем разными для разных компонент. Для этого надо написать напр так
Код
C++ (Qt)
float k0 = CalcK0(progress); // вычисление коэффициентов сплайна (зависят только от t)
...
float red = start.red * k0 + start.red_ctl1 * k1 + end.red_ctl0 * k2 + end.red * k3;
 
Причем progress должно быть оригинальным временем нормированным на сегменте (а не тем что вычисляет QEasyCurve, она здесь бесполезна). Но все равно рез-т зависит не только от типа данных, но и от типа сплайна. Поэтому вся затея с "таблицей интерполяторов" теряет смысл, поживиться с готового класса тут нечем


Название: Re: оператор [] для union
Отправлено: Авварон от Май 19, 2018, 10:41
Фейспалм2.жпг


Название: Re: оператор [] для union
Отправлено: Igors от Май 19, 2018, 11:11
Если этот пример (http://www.prog.org.ru/index.php?topic=31554.msg233458#msg233458) - не предложение, то я уже и не знаю, что можно назвать предложением :)
И тогда и сейчас с удовольствием посмотрел Ваш пример. Нарисовали красиво, много всяких интересных бубочек что я не употребляю. За это спасибо. Но вот с "сутью", т.е.содержательной частью.. ну как-то и говорить неудобно. Это ж просто-напросто.. наследование :) Которое кстати не имеет никакого отношения ни к новым стандартам, ни к std вообще. В данном случае его цель - замкнуть темплейтовскую заразу на базовом классе и общаться с темплейт-реализациями через него. Я не раз применял эту схему, да и все присутствующие наверняка тоже. Ну ладно, если это "предложение" - давайте немного пожуем. Вот огрызок чтобы было перед глазами
Код
C++ (Qt)
struct AbstractCurve
{
...
};
 
template <class Key, class Point, class Option = EmptyOption>
struct Curve final : public AbstractCurve
{
   struct Data
   {
       Key key;
       Point point;
       Option option;
   };
 ...
   using Container = vector<Data>;
   Container data;
...
};
Ну во-первых каждый чих надо оборачивать в базовый виртуал. Число эл-тов в контейнере - перекрытый виртуал, доступ к Key (у простых людей double, время) - опять виртуал и так все-все

Во-вторых, не решается главная проблема - доступ к элементу(ам). Да, часто вызывающий знает какой тип должен быть и может запросить его с темплейт аргументом (напр get<double>). Но часто и нет, чем инстанциироваться - неизвестно. Напр обменять местами 2 эл-та? Ну ладно, так еще можно через базовый виртуал (с натяжкой). Но вот присвоить один эл-т другому - и такой виртуал тащить? Видимо подозревая об этом Вы заметили
Соответственно нужно стремиться к методам в AbstractCurve, которые не зависят от типов данных кривых:
Это идет вразрез с общепринятой концепцией контейнеров. Получается контейнер где просто так эл-т не получить, как это? Заметим что даже наследование от контейнера обычно порицается, мол, действуйте хвункторами). Хотя часто напрасно

Сравним эту схему с простецкой в Qt (детали typedef опускаем)
Код
C++ (Qt)
QVector<QPair<TimeValue, QVariant> >
Ну согласитесь, ведь намного приятнее отой бандуры с виртуалами. Оберток - никаких, если вызывающий знает тип - он может инстанциироваться через вариант, но даже если не знает - QVariant он получит.

Про интерполятор уже что-то было. Не зашло Улыбающийся.
Ой, ну то было так, "не подумавши", тут можно только поулыбаться вместе  :)


Название: Re: оператор [] для union
Отправлено: Авварон от Май 20, 2018, 10:34
Фейспалм2.жпг
Так вот, я предлагаю это, а не то, что вы написали:

Код:
class ColorInterpolator : public AbstractInterpolator
{
ColorInterpolator(const MyColor &start, const MyColor &end, Hint hint):
    _start(start), _end(_end), _hint(hint)
{
}

QVariant interpolate(qreal progress) override
{
// красная компонента
    float k0 = CalcK0(_hint, progress); // вычисление коэффициентов сплайна (зависят только от t).
    // _hint - это что вам захочется, тип кривой (и тогда внутре будет свитч по типу кривой)
    // или модно передать std::function() которая будет вычислять эти ваши k.
    // или это просто массив будет
    // тут уж вам виднее, как удобнее считать коэффициенты
     ...
    float red = _start.red * k0 + _start.red_ctl1 * k1 + _end.red_ctl0 * k2 + _end.red * k3;
// др компоненты
    ...
    return MyColor(red, green, blue);
}

private:
};

Идея в том, что ВСЕ необходимые неизменяемые параметры передаются в конструктор.
По аналогии с лямбдой - захватываем контекст (опорные цвета, коэффициенты), а сама лямбда зависит только от t:
Код:
auto interpolate[k1, k2, k3, start, end](qreal time) { return /*ваша форумула*/; };
Только классом с виртуалом.
Можно без виртуала, можно std::function так и таскать и написать классов-функторов, которые и засунуть в эту функцию.
Главное, что вызов из был унифицирован - для параметра Key мы вызывали interpolate(key) { /*тут вызов этой std::function или класса нашего с виртуалом*/} и на выходе имели map<Key, Variant> которая полностью описывает состояние.


Название: Re: оператор [] для union
Отправлено: ViTech от Май 20, 2018, 11:53
Число эл-тов в контейнере - перекрытый виртуал, доступ к Key (у простых людей double, время) - опять виртуал и так все-все

Во-вторых, не решается главная проблема - доступ к элементу(ам). Да, часто вызывающий знает какой тип должен быть и может запросить его с темплейт аргументом (напр get<double>). Но часто и нет, чем инстанциироваться - неизвестно. Напр обменять местами 2 эл-та? Ну ладно, так еще можно через базовый виртуал (с натяжкой). Но вот присвоить один эл-т другому - и такой виртуал тащить? Видимо подозревая об этом Вы заметили
Соответственно нужно стремиться к методам в AbstractCurve, которые не зависят от типов данных кривых:
Это идет вразрез с общепринятой концепцией контейнеров. Получается контейнер где просто так эл-т не получить, как это? Заметим что даже наследование от контейнера обычно порицается, мол, действуйте хвункторами). Хотя часто напрасно

AbstractCurve - это не контейнер. Контейнер Curve::data находится в классе-реализации Curve. Это может быть vector<Data>, а может быть БД на сервере на противоположной стороне планеты. Про это я уже писал (http://www.prog.org.ru/index.php?topic=31554.msg233512#msg233512) и смысла повторяться не вижу. Мы уже сошлись на том, что я любитель "маленьких, но по три", а Вы "больших, но по пять" :).

Сравним эту схему с простецкой в Qt (детали typedef опускаем)
Код
C++ (Qt)
QVector<QPair<TimeValue, QVariant> >
Ну согласитесь, ведь намного приятнее отой бандуры с виртуалами. Оберток - никаких, если вызывающий знает тип - он может инстанциироваться через вариант, но даже если не знает - QVariant он получит.

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


Название: Re: оператор [] для union
Отправлено: Igors от Май 20, 2018, 12:20
    // _hint - это что вам захочется, тип кривой (и тогда внутре будет свитч по типу кривой)
Внутренние данные (неизменяемые при интерполяции) зависят от типа сплайна. Напр для Безье это red_ctl0 и red_ctl1, но для TCB сплайна это уже t, c и b (3 числа на точку). Поэтому хинты бесполезны, нельзя интерполировать заданный тип кривой не имея нужных параметров в ее точках.

Как я понял, задумка QVariantAnimation в том что QEasyCurve разберется с математикой/сплайнами и выдаст progress который потом используется для линейной интерполяции двух QVariant. Мы можем это изменить сказав QEasyCurve выдавать оригинальное время и написав свою (НЕлинейную) интерполяцию. Этот вызов может выглядеть точно так же, напр
Код
C++ (Qt)
QVariant Interpolate( const MyData & c1, const MyData & c2. double t );
Но тогда что мы имеем с QVariantAnimation ? Да ровным счетом ничего, он бесполезен. Схема "сплайны отдельно, данные отдельно"  слишком красива чтобы быть правдой.

Типов данных к меня 3 , типов сплайна 5. Тупо расписать 3*5 = 15 классов - ну это уже не "перетерпеть", это просто безграмотно. К тому же там совсем не одна интерполяция, нужно апдейтить сплайн на изменения настраиваемых параметров и/или просто значений в точках (если они имеют флажок "автомат"),

Короче - надо обобщать, вот и решил посоветоваться со знатоками которые в курсе всего нового. Ну пока поступило одно предложение - хапнуть готовый класс из букваря. Та, на жаль, моiх бананiв там нема  :'(


Название: Re: оператор [] для union
Отправлено: Авварон от Май 20, 2018, 16:30
Ну пока поступило одно предложение - хапнуть готовый класс из букваря. Та, на жаль, моiх бананiв там нема  :'(

10й раз - я привел ПРИМЕР API а не сказал взять класс из букваря. Или у вас с чтением проблемы?

Типов данных к меня 3 , типов сплайна 5. Тупо расписать 3*5 = 15 классов - ну это уже не "перетерпеть", это просто безграмотно.

Распишите 5 классов в 4х мерном просранстве и сделайте 3 конвертатора из 4хмерного пространства в нужный тип. Склеивая один с другим, получите 15 вариантов.


Название: Re: оператор [] для union
Отправлено: Igors от Май 21, 2018, 06:00
10й раз - я привел ПРИМЕР API а не сказал взять класс из букваря. Или у вас с чтением проблемы?
Не горячитесь. Хоть бы и взять - в этом нет ничего плохого. Просто не вижу ни как взять, ни как "подсмотреть идею". Если у нас есть напр вызов (уже устал его писать)
Код
C++ (Qt)
QVariant Interpolate( const Variant & c1, const Variant & c2, double t );
То и задача решена, никакие классы не нужны. Пример кода для конкретного типа данных и конкретного сплайна приводил выше. Проблема как это сделать с разнообразными комбинациями данных и сплайнов.

Распишите 5 классов в 4х мерном просранстве и сделайте 3 конвертатора из 4хмерного пространства в нужный тип. Склеивая один с другим, получите 15 вариантов.
"Прошу исполнить"  :)

Ну и мы несколько углубились в детали (сплайнов). Изначально рассматривалась только задача хранения таких разнообразных данных в контейнере.


Название: Re: оператор [] для union
Отправлено: Igors от Май 21, 2018, 06:07
Если Вам эта штука приятнее отой бандуры с виртуалами, так и пользуйтесь на здоровье :).
И не подумаю :) Ведь "внутренних" методов у такого контейнера масса, и на каждом разрывать QVariant - проще застрелиться. Вот я и предлагаю для общения с классом использовать вариант, а внутри - темплейтшину. Не пойму почему такое простое и естественное (на мой взгляд) решение осуждается. Ну да ладно, а что взамен ?
Ничего пока не услышал  :)


Название: Re: оператор [] для union
Отправлено: ViTech от Май 21, 2018, 11:52
И не подумаю :) Ведь "внутренних" методов у такого контейнера масса, и на каждом разрывать QVariant - проще застрелиться. Вот я и предлагаю для общения с классом использовать вариант, а внутри - темплейтшину. Не пойму почему такое простое и естественное (на мой взгляд) решение осуждается. Ну да ладно, а что взамен ?
Ничего пока не услышал  :)

Вы хочете задачек? Их есть у меня! :) Если воспринимать высказывание из этого сообщения (http://www.prog.org.ru/index.php?topic=32020.msg236304#msg236304) буквально, т.е. напрямую транслировать из русского языка в С++, что Вы в нём видете/слышите (не видите/не слышите)?

Давайте оформлю это высказывание немного по другому:
1. работать с контейнерами из элементов Value, Coord, Color:
1.1. по отдельности;
1.2. в compile-time в составе:
1.2.a. структуры,
1.2.b. tuple;
1.3. в run-time в составе vector.
2. Как для этого примеры операторов из моего VarData органично расширяются для контейнеров.
3. Как можно std::any и его визитёров применять, чтобы в vector  в run-time добавлять различные контейнеры данных, если с проектированием голову особо ломать не хочется.


Название: Re: оператор [] для union
Отправлено: Авварон от Май 21, 2018, 13:34
"Прошу исполнить"  :)

Код:
class LinearInterpolator : public AbstractInterpolator
{
    LinearInterpolator(QVector4D start, ... /*тут */)
    QVector4D interpolate(double time) override
    {
         // тут считаем кривую в 4d в зависимости от опорных параметров, прееданных в конструктор
    }
}

class ColorConverter : public AbstractConverter
{
    ColorConverter(AbstractInterpolator *interpolator) {...}
    Variant interpolate(double time)  override
    {
          auto v = _interpolator()->interpolate(double);
          return Color(v.x(), v.y(), v.z());
    }
}

Ну и дальше кладем в мапу как хотим.
Как менять интерполяторы - это уже к вам, в зависимости от тычек в UI или как там удобно.
В идеале, к каждой проперте привязан интерполятор и конвертер.


Название: Re: оператор [] для union
Отправлено: Igors от Май 22, 2018, 14:28
Ну и дальше кладем в мапу как хотим.
Далась Вам та мапа.. 
Код
C++ (Qt)
class LinearInterpolator : public AbstractInterpolator
{
   LinearInterpolator(QVector4D start, ... /*тут */)
   QVector4D interpolate(double time) override
...
 
На QVector4D дело не кончится, есть еще 2 др типа данных. А для сплайнов выше линейного это даже не QVector4D, есть еще опции/настройки сплайна. Да и вообще зачем выделять сущность/класс "интерполятор"? Какую смысловую нагрузку он несет? Элемент данных хранит и опции сплайна (нужные для интерполяции), ну так почему бы и не поручить интерполяцию ему же? А заодно и др методы для работы со сплайном. А так, ну да, можно создать мапу с 3*5 = 15 интерполяторами, но это не есть хорошо

Вы хочете задачек?
:) Ну вообще-то нет, надо заниматься проектом. Просто (в очередной раз) возникла задача "универсальный контейнер", вот решил поинтересоваться как ее вообще решают

Давайте оформлю это высказывание немного по другому:
1. работать с контейнерами из элементов Value, Coord, Color:
1.1. по отдельности;
1.2. в compile-time в составе:
1.2.a. структуры,
1.2.b. tuple;
1.3. в run-time в составе vector.
2. Как для этого примеры операторов из моего VarData органично расширяются для контейнеров.
3. Как можно std::any и его визитёров применять, чтобы в vector  в run-time добавлять различные контейнеры данных, если с проектированием голову особо ломать не хочется.
Не было у меня никаких планов чего-то еще добавлять, а о всяких туплах даже не помышлял  :)  Разве термин "контейнер" не самодостаточен? Читать/писать/добавлять/удалять эл-ты - любой контейнер так или иначе реализует этот ф-ционал. Также понятно что если данные разнотипны, то должны быть ограничения, вопрос как их минимизировать. Напр присвоить один эл-т другому без геморроя.  Хорошо хоть в этот раз обошлось ьез реплик типа
Цитировать
С++ типизированный язык, поэтому выражение "универсальный контейнер" - чушь!
:)


Название: Re: оператор [] для union
Отправлено: Авварон от Май 22, 2018, 15:08
Код
C++ (Qt)
class LinearInterpolator : public AbstractInterpolator
{
   LinearInterpolator(QVector4D start, ... /*тут */)
   QVector4D interpolate(double time) override
...
 
На QVector4D дело не кончится, есть еще 2 др типа данных.

Мне кажется, или 3х компонентный цвет включен в QVector4D (просто 1 компонента 0), а double - тем более? Или я чего-то не понимаю, как всегда в исходных условиях?
Что, нельзя интерполировать 1 дабл в 4хмерном пространстве?


Название: Re: оператор [] для union
Отправлено: ViTech от Май 22, 2018, 18:33
Практическая часть зашла в тупик, давайте в лирическую.

Просто (в очередной раз) возникла задача "универсальный контейнер"...

Цитировать
    Один контейнер, чтоб править всеми,
    Один главнее всех,
    Один сберёт всех вместе
    И заключит во тьме.

"Моя прелесть..." (с)

Был такой "универсальный контейнер", да спалили его в недрах Ородруина, чтоб тёмным силам не достался. Кстати, персонаж, который его очень сильно жаждал, последовал туда же, в недра.



Название: Re: оператор [] для union
Отправлено: Igors от Май 23, 2018, 09:01
Мне кажется, или 3х компонентный цвет включен в QVector4D (просто 1 компонента 0), а double - тем более?
Кажется, QVector4D хранит 4-байтовые флоты.

Был такой "универсальный контейнер", да спалили его в недрах Ородруина, чтоб тёмным силам не достался. Кстати, персонаж, который его очень сильно жаждал, последовал туда же, в недра.
Вот объясните мне, откуда такое "скептическое" (мягко говоря) отношение к задаче которая возникает "по жизни", т.е. объективно. Ну ладно, тут какие-то сплайны, вот более простой пример

Некоторые части кода (часто плагины, исходников нет) хранят координаты/вектора как тройки float, другие - как тройки double. Более того, один класс хранит одни данные в double, др в float, и на мульенах эл-тов это совершенно обоснованно. Так что мне, все перегонять в double, что ли? Это ни в какие ворота не лезет. Вот Вам и "универсальный контейнер", хочу я или нет, а делать его надо. Не нравится термин - да ради бога, предложите/используйте свой, дело не в терминах. Но чего "фыркать"-то?  :)


Название: Re: оператор [] для union
Отправлено: ViTech от Май 23, 2018, 10:06
Некоторые части кода (часто плагины, исходников нет) хранят координаты/вектора как тройки float, другие - как тройки double. Более того, один класс хранит одни данные в double, др в float, и на мульенах эл-тов это совершенно обоснованно. Так что мне, все перегонять в double, что ли? Это ни в какие ворота не лезет. Вот Вам и "универсальный контейнер", хочу я или нет, а делать его надо. Не нравится термин - да ради бога, предложите/используйте свой, дело не в терминах. Но чего "фыркать"-то?  :)

Так чем Вам стандартные контейнеры (http://en.cppreference.com/w/cpp/container) не универсальны? :) Если не можете для них писать обобщённые/специализированные алгоритмы, то это не проблема контейнеров. Можете описать спецификацию Вашего "универсального контейнера"? Для образца, вот концепт SequenceContainer (http://en.cppreference.com/w/cpp/concept/SequenceContainer).