Comments 42
Велосипедисты, Сталин дал приказ!
Велосипедисты, зовёт Отчизна нас!
Обажаю подобные штуки для С++, спасибо.
Boost multi_index на порядок функциональнее и позволяет создавать множество индексов на данные не двигая в памяти сами данные. И главное - читый C++, никаких макросов.
И поясните пожалуйста, что за способ доступа к полям структуры вы предлагаете без макросов? Знаю, что есть тип указателя на метод класса, который можно использовать в шаблоннах, но его использование, это нечто жуткое, конструкуции будут многоэтажными.
А на счет multi_index, спасибо, позже посмотрю, что можно от-туда взять себе в пользование.
Вот если бы приводили примеры, как делать такие же штуки, не обременяя многоэтажными выражениями, было бы замечательно.
И поясните пожалуйста, что за способ доступа к полям структуры вы предлагаете без макросов? Знаю, что есть тип указателя на метод класса, который можно использовать в шаблоннах, но его использование, это нечто жуткое, конструкуции будут многоэтажными.
Что-нибудь типа такого? (навскидку):
#include <iostream>
struct Row
{
int id;
double value;
};
template<typename R, typename T>
auto &getMemberRef(const R &row, T member)
{
return row.*member;
}
int main()
{
Row item = {1, 2.2};
std::cout << getMemberRef(item, &Row::id)
<< " " << getMemberRef(item, &Row::value) << std::endl;
}
#include <iostream>
struct Row
{
int id;
double value;
};
int main()
{
Row item = {1, 2.2};
std::cout << item.id << " " << item.value << std::endl;
}
Зачем здесь прилепили getMemberRef это не понятно.
А вот если бы показали, как суммировать, сортировать, поиск значения. Как это все раздувается и обвешивается дополнительными конструкциями, и код становится ради кода, а не ради результата.
getMemberRef
- это как пример того, что можно сделать вместо вашего генератора лямбд на макросах (то что у вас называется COLUMNS
) чисто средствами языка. А в плане остального вам уже предлагали посмотреть на Boost Multi-index.
Будет интересно посмотреть на обвес, когда вы попробуете написать поиск по двум колонкам.
UseCols::findFirst(table,
[](auto& item) { return std::tuple(item.f1, item.f2); },
2, 3);
Вот мой вариант, без макросов. А у вас как будет? Весь код не обязательно, только сам поиск, и объявления дополнительных функций, если таковые нужны. Но если доп.функции отсылаются к типу Row, то это прицеп раздувающий код, а не либу.
Например так:
template<typename... Ts>
auto createMemberRefAccessor(Ts... members)
{
return [members...](auto &row) {
return std::forward_as_tuple(row.*members...);
};
}
UseCols::findFirst(table,
createMemberRefAccessor(&Row::id, &Row::value),
2, 3);
P.S. Я не касаюсь пока самих функций поиска, я просто хочу продемонстрировать, на что можно заменить макросы-генераторы, пользуясь исключительно средствами языка.
А зачем вообще макросы?
Одни могут и перочинным ножичком себя покалечить. Другие могут ходить с ружьем десятки лет, и не отстреливать себе ногу, но получая прибыль от этого большую, чем если бы ходили с перочинным ножиком.
Плохой пример. #pragma once же лучше в любом случае. А если можно без макроса, то вообще хорошо.
Добавлю. Ваш макрос выглядит как раз сложным. Я понимаю простой макрос как азерт или тест, когда надо только прилепить номер строчки.
У #pragma once
свои проблемы. Во-первых, она не везде есть. Во-вторых, она не работает правильным образом, если включаемый файл имеет несколько имён (скажем через симлинки) и одна часть кода включает его под одним именем, а другая - под другим.
template<typename R, typename F1, typename F2, typename V1, typename V2>
auto& findFirst(const std::vector<R>& table, F1 f1, F2 f2, V1 v1, V2 v2)
{
for (auto& i : table)
if (i.*f1 == v1 && i.*f2 == v2) return i;
return R{};
}
auto found = findFirst(table, &Row::id, &Row::value, 1, 7.0f);
Я так понял нужно предоставить генератор функций/лямбд которые принимали бы row и выдавали бы tuple со ссылками на перечисленные элементы этого row, вот выше пример как это сделать без макросов.
возврат ссылки на локальное значение в случае не найденностиДа, проблемка. А как надо?
static R value;
return value;
}
Или указатель на элемент списка, т.е. тип decltype(&*list.begin()), и в случае не найденности nullptr.
Ещё один вариант — вернуть std::optional<R&>
В любом случае, возврат ссылки будет не стабильным и не красивым для этого случая. Общеприменимая практика это возврат итератора.
вариант — вернуть std::optional<R&>А можно пример?
std::optional<R&> op;
Не компилируется.Вы слышали про std::sort который принимает любой компаратор? Про то что можно создавать ссылки на поля, типаtemplate<typename C, typename T>
auto Foo(T C::* value) {
return 10;
}
Зачем всё сделано на макросах?
Так же привел три варианта организации передачи полей: макросом, просто лямбдой, и как позже подсказали, генератор лямбд memberAccessor, как раз на указателях на поля. Выбирайте любой, какой больше нравится.
Если Вы про что-то другое, то напишите полный пример. Незабудьте его проверить на компилируемость, а то, то что выше, не похоже на компилируемое.
Может вы хотя бы годболтом научитесь пользоваться? Или вы на глаз компилируете?
легко запутаться, что является источником ошибок
То ли дело макросы, там нет источников ошибок и всё просто, а главное производительно, современно и понятно
Заглянул в реализацию - шаблоны разеделены на хедеры и cpp, всё, это уже автоматически ifndr, не используются универсальные ссылки вообще
Я например несколько недоумевал, почему не компилируется такой код
enum class ITERATOR_RESULT { SUCESS, ERROR, EOF };
Оказалось, что ERROR и EOF опрелены макросами в windows.h
У меня бы члены подобного энума имели бы префикс «IR_». И от таких эксцессов защищает, и немного повышает читаемость и самодокументируемость кода.
Я бы скорее посоветовал ничего, кроме макросов не называть в ALL_CAPS. А уже макросам обязательно давать префиксы и вообще минимизировать их количество.
Как уже правильно заметил qw1, тут префикс будет просто повторяться дважды, соответственно читаемость и самодокументируемость никак не улучшит.
В MSVC с недавних пор починили препроцессор и теперь он соответствует стандарту: https://docs.microsoft.com/en-us/cpp/preprocessor/preprocessor-experimental-overview?view=msvc-160
С++: работа с таблицами