Сообщение Re: Вопрос по метапрограммированию от 13.06.2019 11:55
Изменено 13.06.2019 12:06 rg45
Re: Вопрос по метапрограммированию
Здравствуйте, RiNSpy, Вы писали:
RNS>Вообщем, проблема такая. Есть некое API, которое пишет куда-то вектора данных разных типов, которые я ему даю. Что-то вроде такого:
RNS>Мне надо обработать тонны подобных векторов и записать их методом Dataset::write. Для примера:
RNS>Проблема в том, что у меня этих веторов очень много, они разных типов. Их количество, имена и типы иногда меняются в спецификации, до этапа компилирования, и мне приходится их вручную менять в коде. Код получается очень некрасивый.
RNS>Хотелось бы что-то такое сделать, чтобы я мог где-то в одном месте определить их имена и типы, а потом создать вектора, DataSet'ы, вызвать write(...) в цикле. То есть если имена и типы поменяются, чтобы мне не надо было их менять вручную в 3х местах, и если у меня этих векторов 100 штук, чтобы не плодить 300 строк кода.
RNS>Как мне это элегантнее сделать?
Фактически задача сводится к тому, чтобы связать имена колонок с их типами, все остальное раскручивается на шаблонах совершенно унифицировано.
https://ideone.com/lZjCQK
Связка имен с типами делается при помощи введения мнемонических имен, совпадающих с именами колонок (но только без кавычек). Эти имена используются как параметры шаблонов, служаших для доступа к типам, функциям и переменным:
Теперь получить тип DataSet, соответствующий колонке "B", можно при помощи простой конструкции DataSetType<B>. Тип соответствующего вектора — VectorType<B>. Имя колонки — column_name<B>.
Помимо шаблонов типов можно так же определить шаблоны глобальных переменных, если они нужны. И предоставить дополнительные утилиты для работы с ними:
Теперь заполнить необходимые dataset-ы, все или выборочно, можно простыми выражениями:
Я нигде не использовал column_names потому, что не понял, зачем они нужны и какой у них скоуп. Их формирование без труда можно впихнуть внутрь макроса DEFINE_COLUMN, если хочется.
Полный текст примера здесь: https://ideone.com/lZjCQK
RNS>Вообщем, проблема такая. Есть некое API, которое пишет куда-то вектора данных разных типов, которые я ему даю. Что-то вроде такого:
RNS>Мне надо обработать тонны подобных векторов и записать их методом Dataset::write. Для примера:
RNS>Проблема в том, что у меня этих веторов очень много, они разных типов. Их количество, имена и типы иногда меняются в спецификации, до этапа компилирования, и мне приходится их вручную менять в коде. Код получается очень некрасивый.
RNS>Хотелось бы что-то такое сделать, чтобы я мог где-то в одном месте определить их имена и типы, а потом создать вектора, DataSet'ы, вызвать write(...) в цикле. То есть если имена и типы поменяются, чтобы мне не надо было их менять вручную в 3х местах, и если у меня этих векторов 100 штук, чтобы не плодить 300 строк кода.
RNS>Как мне это элегантнее сделать?
Фактически задача сводится к тому, чтобы связать имена колонок с их типами, все остальное раскручивается на шаблонах совершенно унифицировано.
https://ideone.com/lZjCQK
Связка имен с типами делается при помощи введения мнемонических имен, совпадающих с именами колонок (но только без кавычек). Эти имена используются как параметры шаблонов, служаших для доступа к типам, функциям и переменным:
template <typename> struct ColumnTraits;
#define DEFINE_COLUMN(name, type) class name; template<> struct ColumnTraits<name> { using ColumnType = type; static constexpr const char* column_name = #name; };
template <typename Column>
constexpr const char* column_name = ColumnTraits<Column>::column_name;
template <typename Column>
using ColumnType = typename ColumnTraits<Column>::ColumnType;
template <typename Column>
using VectorType = std::vector<ColumnType<Column>>;
template <typename Column>
using DataSetType = DataSet<ColumnType<Column>>;
DEFINE_COLUMN(A, int)
DEFINE_COLUMN(B, float)
DEFINE_COLUMN(C, double)
DEFINE_COLUMN(D, int)
DEFINE_COLUMN(E, float)
DEFINE_COLUMN(F, double)
Теперь получить тип DataSet, соответствующий колонке "B", можно при помощи простой конструкции DataSetType<B>. Тип соответствующего вектора — VectorType<B>. Имя колонки — column_name<B>.
Помимо шаблонов типов можно так же определить шаблоны глобальных переменных, если они нужны. И предоставить дополнительные утилиты для работы с ними:
// You can even define templates for flobal variables, if it's necessary:
template <typename Column>
VectorType<Column> global_values;
template <typename Column>
DataSetType<Column> global_dataset(column_name<Column>);
// Yoy can provide utility for global writhing by specified types:
template <typename...Columns>
void write_values(const VectorType<Columns>&...values)
{
std::initializer_list<int>{ (global_dataset<Columns>.write(values), 0)... };
}
template <typename...Columns>
void write_global_values()
{
write_values<Columns...>(global_values<Columns>...);
}
Теперь заполнить необходимые dataset-ы, все или выборочно, можно простыми выражениями:
global_dataset<D>.write({1, 2, 3, 4, 5});
global_dataset<B>.write(global_values<B>);
write_values<A, C>({1, 2}, {3.14, 0.1});
write_global_values<F, A, C, E>();
Я нигде не использовал column_names потому, что не понял, зачем они нужны и какой у них скоуп. Их формирование без труда можно впихнуть внутрь макроса DEFINE_COLUMN, если хочется.
Полный текст примера здесь: https://ideone.com/lZjCQK
Re: Вопрос по метапрограммированию
Здравствуйте, RiNSpy, Вы писали:
RNS>Вообщем, проблема такая. Есть некое API, которое пишет куда-то вектора данных разных типов, которые я ему даю. Что-то вроде такого:
RNS>Мне надо обработать тонны подобных векторов и записать их методом Dataset::write. Для примера:
RNS>Проблема в том, что у меня этих веторов очень много, они разных типов. Их количество, имена и типы иногда меняются в спецификации, до этапа компилирования, и мне приходится их вручную менять в коде. Код получается очень некрасивый.
RNS>Хотелось бы что-то такое сделать, чтобы я мог где-то в одном месте определить их имена и типы, а потом создать вектора, DataSet'ы, вызвать write(...) в цикле. То есть если имена и типы поменяются, чтобы мне не надо было их менять вручную в 3х местах, и если у меня этих векторов 100 штук, чтобы не плодить 300 строк кода.
RNS>Как мне это элегантнее сделать?
Фактически задача сводится к тому, чтобы связать имена колонок с их типами, все остальное раскручивается на шаблонах совершенно унифицировано.
https://ideone.com/lZjCQK
Связка имен с типами делается при помощи введения мнемонических имен, совпадающих с именами колонок (но только без кавычек). Эти имена используются как параметры шаблонов, служаших для доступа к типам, функциям и переменным:
Теперь получить тип DataSet, соответствующий колонке "B", можно при помощи простой конструкции DataSetType<B>. Тип соответствующего вектора — VectorType<B>. Имя колонки — column_name<B>.
Помимо шаблонов типов можно так же определить шаблоны глобальных переменных, если они нужны. И предоставить дополнительные утилиты для работы с ними:
После этого уже не нужно определять индивидуально для каждой колонки: intValues, floatValues, doubleValues, intDataset, floatDataset, doubleDataset... мы все уже сделали — парой шаблоннов переменных! И доступиться к ним теперь можно при помощи простых выражений: global_dataset<A>, global_values<B>...
И заполнить необходимые dataset-ы, все или выборочно, можно тоже простыми выражениями:
Я нигде не использовал column_names потому, что не понял, зачем они нужны и какой у них скоуп. Их формирование без труда можно впихнуть внутрь макроса DEFINE_COLUMN, если хочется.
Полный текст примера здесь: https://ideone.com/lZjCQK
RNS>Вообщем, проблема такая. Есть некое API, которое пишет куда-то вектора данных разных типов, которые я ему даю. Что-то вроде такого:
RNS>Мне надо обработать тонны подобных векторов и записать их методом Dataset::write. Для примера:
RNS>Проблема в том, что у меня этих веторов очень много, они разных типов. Их количество, имена и типы иногда меняются в спецификации, до этапа компилирования, и мне приходится их вручную менять в коде. Код получается очень некрасивый.
RNS>Хотелось бы что-то такое сделать, чтобы я мог где-то в одном месте определить их имена и типы, а потом создать вектора, DataSet'ы, вызвать write(...) в цикле. То есть если имена и типы поменяются, чтобы мне не надо было их менять вручную в 3х местах, и если у меня этих векторов 100 штук, чтобы не плодить 300 строк кода.
RNS>Как мне это элегантнее сделать?
Фактически задача сводится к тому, чтобы связать имена колонок с их типами, все остальное раскручивается на шаблонах совершенно унифицировано.
https://ideone.com/lZjCQK
Связка имен с типами делается при помощи введения мнемонических имен, совпадающих с именами колонок (но только без кавычек). Эти имена используются как параметры шаблонов, служаших для доступа к типам, функциям и переменным:
template <typename> struct ColumnTraits;
#define DEFINE_COLUMN(name, type) class name; template<> struct ColumnTraits<name> { using ColumnType = type; static constexpr const char* column_name = #name; };
template <typename Column>
constexpr const char* column_name = ColumnTraits<Column>::column_name;
template <typename Column>
using ColumnType = typename ColumnTraits<Column>::ColumnType;
template <typename Column>
using VectorType = std::vector<ColumnType<Column>>;
template <typename Column>
using DataSetType = DataSet<ColumnType<Column>>;
DEFINE_COLUMN(A, int)
DEFINE_COLUMN(B, float)
DEFINE_COLUMN(C, double)
DEFINE_COLUMN(D, int)
DEFINE_COLUMN(E, float)
DEFINE_COLUMN(F, double)
Теперь получить тип DataSet, соответствующий колонке "B", можно при помощи простой конструкции DataSetType<B>. Тип соответствующего вектора — VectorType<B>. Имя колонки — column_name<B>.
Помимо шаблонов типов можно так же определить шаблоны глобальных переменных, если они нужны. И предоставить дополнительные утилиты для работы с ними:
// You can even define templates for flobal variables, if it's necessary:
template <typename Column>
VectorType<Column> global_values;
template <typename Column>
DataSetType<Column> global_dataset(column_name<Column>);
// Yoy can provide utility for global writhing by specified types:
template <typename...Columns>
void write_values(const VectorType<Columns>&...values)
{
std::initializer_list<int>{ (global_dataset<Columns>.write(values), 0)... };
}
template <typename...Columns>
void write_global_values()
{
write_values<Columns...>(global_values<Columns>...);
}
После этого уже не нужно определять индивидуально для каждой колонки: intValues, floatValues, doubleValues, intDataset, floatDataset, doubleDataset... мы все уже сделали — парой шаблоннов переменных! И доступиться к ним теперь можно при помощи простых выражений: global_dataset<A>, global_values<B>...
И заполнить необходимые dataset-ы, все или выборочно, можно тоже простыми выражениями:
global_dataset<D>.write({1, 2, 3, 4, 5});
global_dataset<B>.write(global_values<B>);
write_values<A, C>({1, 2}, {3.14, 0.1});
write_global_values<F, A, C, E>();
Я нигде не использовал column_names потому, что не понял, зачем они нужны и какой у них скоуп. Их формирование без труда можно впихнуть внутрь макроса DEFINE_COLUMN, если хочется.
Полный текст примера здесь: https://ideone.com/lZjCQK