+1
- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
struct Test
{
Array<int> intArray;
int fixedIntArray[3];
bool booleanVal;
float flt;
Array<string> stringArray;
ADD_REFLECTION(Test, intArray, fixedIntArray, booleanVal, flt, stringArray);
};
struct SuperTest
{
Array<string> strArr;
int foo;
string str;
Array<short> vals;
double dbl;
Test tests[3];
ushort bar;
ADD_REFLECTION(SuperTest, strArr, foo, str, vals, dbl, tests, bar);
};
int main()
{
StringView structText = R"({
.strArr = {"str1", "ergvwr", "brt"},
.foo = 5,
.str = "gammaker",
.vals = {-4, 66, 432, -95},
.dbl = 3.1415926535897932384626433832795,
{
{
.fixedIntArray = {9, 4, 85},
.stringArray = {"test 0 A", "test 0 B", "test 0 C"},
.booleanVal = true,
.intArray = {43, 54, 36, 76},
.flt = 1.23456,
.flt = 2.34567
},
{
.intArray = {},
.fixedIntArray = {3655456, 234, 3},
.booleanVal = false,
.flt = 2.718281828,
.stringArray = {"test 1 A", "test 1 B"}
},
{
.intArray = {1531, 1253, 16, 634, 236462363},
.fixedIntArray = {9435, 435, 8355},
.booleanVal = false,
.flt = 123.65,
.stringArray = {"test 2 A", "test 2 B", "test 2 C", "test 2 D"}
}
},
.bar = 1025
})";
Data::TextDeserializer deserializer(Data::DataLanguageParams::CStructInitializer, structText);
SuperTest test = deserializer.Deserialize<SuperTest>();
char charBuf[5000];
Data::TextSerializer serializer(Data::DataLanguageParams::Json, Data::TextSerializerParams::Verbose, ArrayRange<char>(charBuf, 5000));
serializer.NestingLevel=-1;
serializer.Serialize(test);
Console.PrintLine(serializer.GetString());
Data::DataLanguageParams rusML;
rusML.RequireFieldAssignments = false;
rusML.AddFieldNameAfterAssignment = false;
rusML.LeftAssignmentOperator = "равно";
rusML.FieldSeparator = " следующее поле";
rusML.LeftFieldNameBeginQuote = null;
rusML.LeftFieldNameEndQuote = null;
rusML.RightFieldNameBeginQuote = null;
rusML.RightFieldNameEndQuote = null;
rusML.StructInstanceOpen = "начало структуры";
rusML.StructInstanceClose = " структура кончилась";
rusML.OneLineCommentBegin = "комментарий:";
rusML.StringQuote="\"";
rusML.CharQuotes = "";
rusML.ArrayOpen = " массив начался ";
rusML.ArrayClose = " кончился массив ";
rusML.ArrayElementSeparator = " дальше";
rusML.FalseTrueNames[0] = "нет";
rusML.FalseTrueNames[0] = "да";
rusML.DecimalSeparator = ',';
serializer = Data::TextSerializer(rusML, Data::TextSerializerParams::Verbose, ArrayRange<char>(charBuf, 5000));
serializer.NestingLevel=-1;
serializer.Serialize(test);
Console.PrintLine(serializer.GetString());
return 0;
}
Сделал автоматический сериализатор с кучей параметров, используя которые можно описать JSON, инициализаторы C'шных и D'шных структур, подмножество XML или какой-нибудь свой кастомный формат. Здесь показана десериализация сишного инициализатора с designated initializers, который почему-то не добавили в C++. Затем полученная структура сериализуется в JSON (его описание в моём хидере, и здесь не приведено), а затем в придуманный мной ради прикола язык разметки rusML, описание которого можно видеть в коде.
Выводит (табы порезались):
{
"strArr" : ["str1", "ergvwr", "brt"],
"foo" : 5,
"str" : "gammaker",
"vals" : [-4, 66, 432, -95],
"dbl" : 3.141592653589789,
"tests" : [
{
"intArray" : [43, 54, 36, 76],
"fixedIntArray" : [9, 4, 85],
"booleanVal" : true,
"flt" : 2.3456699,
"stringArray" : ["test 0 A", "test 0 B", "test 0 C"]
},
{
"intArray" : [],
"fixedIntArray" : [3655456, 234, 3],
"booleanVal" : false,
"flt" : 2.7182817,
"stringArray" : ["test 1 A", "test 1 B"]
},
{
"intArray" : [1531, 1253, 16, 634, 236462363],
"fixedIntArray" : [9435, 435, 8355],
"booleanVal" : false,
"flt" : 123.6499938,
"stringArray" : ["test 2 A", "test 2 B", "test 2 C", "test 2 D"]
}
],
"bar" : 1025
}
начало структуры
strArr равно массив начался "str1" дальше "ergvwr" дальше "brt" кончился массив следующее поле
foo равно 5 следующее поле
str равно "gammaker" следующее поле
vals равно массив начался -4 дальше 66 дальше 432 дальше -95 кончился массив следующее поле
...
Запостил: gammaker,
30 Июля 2016
Bobik 30.07.2016 20:15 # +1
gammaker 30.07.2016 20:41 # 0
Бинарная десериализация у меня тоже есть, но там настраивать нечего, поэтому я решил, что выкладывать её сюда не так интересно будет.
Вообще я собираюсь сделать универсальный бинарный формат, который будет содержать не только сами данные, но и саму структуру этих данных. То есть в нём будет указано, что в нём лежит, и можно будет найти и замапить нужный участок (если он POD) в память, и работать с ним, как с массивом структур. Если не POD, то придётся десериализовать, что будет происходить автоматически, как в этом коде.
Bobik 30.07.2016 20:53 # +2
Думаю, скоро выяснится, что для каких-то задач он плохо применяется.
>Мне не нравится такой подход
А макрос ADD_REFLECTION нравится?
>Кроме того, protobuf - бинарный, а значит, его область применения отличается от того, что здесь выложено
У proto3 него есть "canonical mapping" в json и "textformat", который несколько корявый. В целом, не любой формат, но жить можно.
Кроме того, у всех сгенерированных структур есть дескрипторы, по которым дампер в любое текстовое представление пишется достаточно тривиально.
>содержать не только сами данные, но и саму структуру этих данных
Что, опять же, есть в протобуфе.
>замапить нужный участок (если он POD) в память, и работать с ним, как с массивом структур
То есть работать будет только на одной архитектуре?
bormand 30.07.2016 21:08 # 0
Для многих применений этого достаточно, если файл предполагается читать на той же самой машине.
laMer007 31.07.2016 00:20 # +2
reinterpret_cast<char[sizeof(MyStruct)]>?
gammaker 30.07.2016 22:42 # 0
Есть некоторые вещи, которые ещё не реализованы, потому что мне не нужны, но я всё равно думаю, как бы я их реализовал, и вроде они просто и органично впишутся в тот сериализатор, который уже есть.
Это всего лишь один макрос, вызов которого занимает одну строчку. Всё делается в коде без посторонних утилит. А когда в C++ добавят нормальную рефлексию, если такое когда-нибудь случится, можно будет и макрос убрать. Вроде собирались добавить в C++17, но передумали.
gammaker 30.07.2016 22:42 # 0
Протобуф может и содержит информацию о структуре, но по-любому требует пользоваться своими сгенеренными классами. Я ненавижу кодогенераторы и предпочитаю получать то, что я пишу сам на C++.
Работать будет на всех архитектурах с одинаковой endianess и одинаковыми float'ами вроде как. То есть x86 + ARM уже можно охватить одной версией формата, а под другие архитектуры я во-первых писать не планирую пока, а во-вторых можно свои файлы сделать. Скорее всего у меня в движке будет компилятор, который автоматически будет переводить текстовые файлы в бинарные под нужную архитектуру, сжимать текстуры под нужную платформу и так далее.
bormand 31.07.2016 06:55 # 0
amd64 не поддерживаешь?
gammaker 31.07.2016 10:43 # 0
bormand 31.07.2016 10:49 # 0
gammaker 31.07.2016 11:23 # 0
А моему будущему сериализатору универсального формата будет вообще пофиг на разницу между short, int и long long. Он будет знать всё о типах с обеих сторон и автоматически приведёт тип.
bormand 31.07.2016 11:24 # 0
А если не влезает?
gammaker 31.07.2016 12:03 # 0
bormand 31.07.2016 12:12 # 0
С насыщением до максимума или тупо старшие биты отвалятся?
З.Ы. Лог логом, но я бы всё-таки ошибку загрузки вернул, чтобы потом косяки не полезли.
gammaker 31.07.2016 12:27 # +1
Если лог не пустой, значит ошибка. Никаких дополнительных кодов ошибки не нужно, а исключения я не использую. Лог не глобальный, он не пишется в файл. Он локальный для десериализатора и пишется в строку. То есть если пользователю пофиг на ошибки, он не будет смотреть лог и не узнает о них. Если не пофиг, он выведет лог на консоль, в MessageBox или ещё куда-нибудь, например в глобальный лог-файл. А если пользователь не хочет допускать вообще никаких ошибок, он выдаст ошибку и завершит программу. Вот например:
deserializer.Deserialize<SuperTest>();
if(deserializer.Log!=null) Console.PrintLine("При десериализации произошли следующие ошибки:", endl, deserializer.Log);
guest 30.07.2016 22:28 # 0
Воооот. Вот это дело. Не скупись на метаданные, а то не распарсится ничего.
gammaker 30.07.2016 22:48 # 0
CHayT 30.07.2016 22:51 # +2
Опять метушня? Опять метушня.
kegdan 31.07.2016 07:17 # 0
Два чая этому господину
roman-kashitsyn 31.07.2016 00:21 # +2
В Я нечто похожее используется — называется MMS. Только там метаданные не хранятся — уж больно накладно получается.
Вкратце: есть два вида "значений" мутабельные обычные и иммутабельные замапленные. С помощью первых ты создаёшь в памяти некоторую структуру, сериализуешь её в файл. С помощью вторых ты ммапишь структуру в файл и используешь как есть, без стадии десериализации. Это можно провернуть не только с подами, но и со сложными структурами данных (хэш-таблицы, деревья поиска).
Эта технология используется, например, для доставки здоровенных графов на сервера. Т.е. некий процесс создаёт в памяти граф и сериализует его, сериализованный файл торрентом заливается на тучу машин, после чего кластер синхронно и переключается на новую версию графа с минимальными задержками.
Если интересно — посмотри видео, почитай сорцы.
gammaker 31.07.2016 00:59 # 0
Не понял, как можно мапить не-POD данные из файла. Ну ладно, завтра посмотрю, почитаю.
roman-kashitsyn 31.07.2016 01:21 # +2
Смотря что называть "метаданными" и насколько развита система рантайм-типов. Если хранить метку типа каждого значения, то может получаться накладно.
Допустим, у нас есть статический граф, в котором рёбер в К раз больше, чем вершин (которых Н), представленный для простоты в виде списка смежности.
Предположим, мы сериализуем его в какой-нибудь BSON, который для каждого значения хранит тип. Имеем "массив массивов интов", при этом для каждого инта в каждом массиве мы храним ещё один инт — метку типа "следующее значение — int".
В итоге оверхед как минимум 100%.
Если у нас в системе рантайм-типов есть метка "следующее значение — массив интов". Тогда у нас хранится один "универсальный массив" + N "массивов интов". Оверхед стал меньше — примерно 100 / K %.
gammaker 31.07.2016 02:17 # 0
Я придумал такой формат, который в метаданных позволит описать любую структуру, даже если это структура массивов структур структур массивов строк. Просто в файле будет объявлен такой сложный тип, а потом просто будет на него ссылка и уже сами данные в чистом виде и без всяких метаданных. Там можно будет замутить любую структуру данных, в том числе и хеш-таблицы, списка и так далее, и напрямую использовать из файла, как сделали в яндексе.
Недостатков у этого метода по-моему вообще нет, если не считать сложность реализации. Файлы весят мало, доступ самый быстрый, версионирование и расширяемость на высоте, автоматическая десериализация.
Сейчас пока только есть письменное описание формата - где какие байты в каком порядке идут и что обозначают. Собираюсь скоро начать реализовывать его на базе своей уже реализованной сериализации.
CHayT 31.07.2016 10:09 # 0
gammaker 31.07.2016 12:08 # 0
https://blog.molecular-matters.com/2014/02/21/schema-based-entity-component-data-for-fast-iteration-times/
Ведь эти схемы имелись в виду или какие-то другие?
Я сначала хотел повторить это у себя, а потом понял, что можно сделать лучше и устранить многие недостатки. Думал, думал, и в итоге пришёл вот к этой сериализации и универсальному формату.
bormand 30.07.2016 20:30 # 0
> 5000
А дефолта на весь массив нету что ли? Неудобно же указывать размер каждый раз. И ведь по-любому 90% кода оборачивает массив целиком.
> char
Ну и вывод типа разве не пригодился бы?
gammaker 30.07.2016 20:33 # +1
meinf 30.07.2016 20:40 # +7
gammaker 30.07.2016 22:24 # 0
Да и вообще вариативные шаблоны - это то ещё извращение. Вряд ли каждый второй крестовик дорос до их использования.
guest 30.07.2016 22:33 # +2
лол
gammaker 30.07.2016 22:59 # 0
Ты правда уверен, что каждый второй крестовик дорос до этого:
http://www.cyberforum.ru/cpp-beginners/thread1658956.html
?
bormand 31.07.2016 07:01 # 0
И не перерос, спрыгнув на boost::preprocessor, который всяко удобней, чем голая макросня.
Там тебе и вертикальное и горизонтальное раскрытие, и функциональщина типа map/filter, и простенькая арифметика...
CHayT 31.07.2016 10:27 # +4
bormand 30.07.2016 22:44 # 0
gammaker 30.07.2016 23:01 # 0
meinf 31.07.2016 00:10 # 0
ну правда, да, по-моему объявления в одну строчку нигде не было
а вообще без твоих сырцов конечно не сказать, но имхо, там и в реализации сильно разгуляться негде: маппер юзающий указатели на члены классов + специальные структуры, макросами собственно и создаваемые, складывающиеся в статический ридонли контейнер внутри класса
gammaker 31.07.2016 00:24 # 0
Я раньше сериализацию делал кортежем указателей на члены, но потом переделал на visitor. С ним короче и вариадик шаблонов не надо. Просто в ADD_REFLECTION добавился метод VisitEachField, а проект, где используется ADD_REFLECTION, даже трогать не надо.
Статический read only контейнер - это просто static const ReflectionField[] массив внутри функции, который возвращается как ArrayRange<const ReflectionField> - пара указателей со всякими удобными методами.
Там ещё перегрузка макросов, которой как бы нет в C\C++, но которую можно реализовать через *опу.
meinf 31.07.2016 01:18 # 0
> это просто static const ReflectionField[]
> пара указателей со всякими удобными методами.
ну в общих чертах я примерно так себе и представляю
> Там ещё перегрузка макросов, которой как бы нет в C\C++, но которую можно реализовать через *опу.
с макросами можно делать много всяких извращений, было бы желание и время
> что по различным соображениям не использую STL, Boost и другие сторонние библиотеки
это на самом деле идеализм, не мне тебя учить, но вот когда ты хочешь переписать прям все все все - это плохо, бусты/етц не осиливаются в одно жало, есть неплохой такой шанс разочароваться
gammaker 31.07.2016 02:24 # 0
meinf 31.07.2016 14:17 # 0
ок, а почему тогда просто не использовать D? удерживают существующие проекты?
gammaker 31.07.2016 15:54 # 0
Во-вторых, там просто катастрофически разрастается бинарник. Меня категорически не устраивает, когда приложение чуть сложнее Hello World'а начинает весить полмегабайта. Многим на это пофиг, но не мне. У меня целый синтезатор midi на C++ весит всего лишь 57 КБ.
В-третьих, поддержка Android. До недавнего времени её не было, но вроде пишут, что появилась тестовая поддержка. Пока сыро, с этим связываться не хочется, но видимо скоро этот недостаток будет полностью устранён.
Ну и в-третьих да, у меня уже очень много всего написано на C++. Я уже не представляю свою жизнь без своих удобных велосипедов, поэтому и их тоже надо будет переводить на D, по крайней мере половину из них. Если бы в D не было всех вышеперечисленных недостатков, я бы наверное переписал свои проекты на него. А так переписывать 20000-30000 строк кода, зная, что придётся смириться с проблемами, которых нет сейчас, не хочется.
Вместо того, чтобы решать все эти проблемы, проще перенести все нужные фичи из D в C++.
j123123 02.08.2016 01:48 # −1
Современные IDE (особенно говновизуальная студия) являются просто дичайшим говном и должны быть выброшены нахуй вместе с этими уродскими плюсами.
https://www.youtube.com/watch?v=N8elxpSu9pw лучше бери пример с этого чувака
gost 31.07.2016 15:52 # 0
>> STL, Boost и другие сторонние библиотеки
Лол.
gammaker 31.07.2016 16:02 # 0
Antervis 30.07.2016 23:36 # +2
А вообще, сдается мне, что код не должен одновременно быть и в продакшене, и на сайте говнокода. Это алогично
Soul_re@ver 30.07.2016 23:41 # +1
kegdan 31.07.2016 07:18 # +1
Я вообще отрицаю любой другой опыт. Слова только все путают
bormand 31.07.2016 07:20 # 0
Солнце крутится вокруг земли, а земля - диск?
kegdan 31.07.2016 07:22 # +1
Кстати солнце крутится вокруг земли и существуют системы отсчета в которых земля - диск
Antervis 31.07.2016 12:07 # 0
gammaker 31.07.2016 12:44 # 0
А в программировании эта поговорка вообще мимо, потому что это такая область, где сразу всё умом не охватишь. Это итеративный процесс, когда сразу, не въехав, хорошо сделать невозможно, а пока не начнёшь делать как-нибудь - не въедешь.
Лично я ни разу не пожалел, что изобретаю велосипеды. Благодаря этому я отлично знаю C++. Мои велики самые быстрые, компактные, удобные и в то же время универсальные. Это не те велосипеды с квадратными колёсами, которые делают начинающие разработчики.
kurwa 31.07.2016 13:34 # +2
CHayT 31.07.2016 14:38 # +1
Не вы ли о Царе мне уши прошумели?
Вам дан был Царь?— так тот был слишком тих:
Вы взбунтовались в вашей луже,
Другой вам дан — так этот очень лих:
Живите ж с ним, чтоб не было вам хуже!
Antervis 31.07.2016 14:14 # 0
Что до строк кода и объема - тут есть момент, не спорю. Впрочем, многие вещи типа QPair/QFunction и пр. могли бы заменить на стандартные версии
gammaker 31.07.2016 16:00 # 0
QPair и QFunction - это капля в море кода. По крайней мере у меня их аналоги занимают очень малую долю от всего кода.
Soul_re@ver 31.07.2016 16:09 # 0
gammaker 31.07.2016 16:26 # 0
template<typename T1, typename T2> struct pair
{
T1 first;
T2 second;
};
По идее все конструкторы и операторы присваивания компилятор сам сгенерирует. Что в таком случае помешает perfect forwarding'у?
pair использую только как затычку, когда лень создавать структуру из двух полей, но нужно пропихивать элементы парами. Но в дальнейшем обычно находится, чем эти затычки заменить, и pair становится ненужным.
Для пары указателей на начало и конец у меня специальный класс ArrayRange, который как раз специально для этого предназначен и очень удобен в использовании.
Soul_re@ver 31.07.2016 16:49 # +1
http://coliru.stacked-crooked.com/a/147065d2d33d3550
Заставь пару <immovable_stone, immovable_stone> работать.
*Насчёт искуственности: многие вещи неперемещаемы после инициализации, вроде мютексов, тасков и прочей хуйни.
gammaker 31.07.2016 17:19 # 0
Я не уверен, что пихать мьютексы и таски в пары - хорошая идея.
Soul_re@ver 31.07.2016 17:34 # 0
Плюс я не уверен, что если бы там не было более сложных типов, то не вызвались бы лишние конструкторы.
Ну и ещё где "не использую STL"? Использовать обобщённую пару, чтобы сделать пару это читерство.
В общем, как поковыряешься с такими проблемами, начинаешь понимать, почему в стандартной библиотеке столько кода. И начинаешь ненавидеть NULL.
kegdan 31.07.2016 17:43 # 0
gammaker 31.07.2016 17:50 # 0
У меня свои кортежи есть. Там правда нет пока integer_sequence. Я думаю вообще избавиться от этих pair, которые всё равно используются в 2,5 мест, а заменить их на кортежи.
А зачем NULL ненавидеть? Просто не надо его использовать и всё.
Я у себя просто не допускаю таких проблем. У меня все объекты перемещаемы и имеют конструктор по умолчанию.
Soul_re@ver 31.07.2016 18:14 # +1
Стандарт разрешает, я хочу. И вообще у нас стандарт написания кода с 1988 г. не менялся, только дополнялся.
> У меня все объекты перемещаемы и имеют конструктор по умолчанию.
А если у объекта в принципе нет логичного значения по умолчанию? Two-stage initialization это дикий зашквар. Некоторые объекты типа атомиков не перемещаемые в принципе. И никах их перемещаемыми не сделать.
> А зачем NULL ненавидеть? Просто не надо его использовать и всё.
Я бы рад, но есть пользователи... Смотри п.1
В общем, если ты пишешь general-purpose библиотеку, то делать её совместимой со всеми существующими и ещё не существующими паттернами разработки придётся. Иначе библиотека идёт нахуй после второй-третьей обнаруженной особенности и берётся нормальная.
Специализированные библиотеки могут чхать на это так как они и так работают в ограниченном множестве случаев.
Кстати, свою замену Концептам уже выкатил? Потому что когда начинаешь документировать свой код и приводить требования/возможности к единообразному виду, обычно заново их изобретаешь. Очень помогают.
gammaker 31.07.2016 18:40 # 0
У меня практически всё перемещаемо. Я специально так делаю, чтобы не было проблем с контейнерами и т.п.. Вроде всегда логичное значение находилось - пустой объект, который не содержит в себе никакого ресурса.
Правда я потом столкнулся с тем, что лямбды оказались неприсваемыми и сделал optional, в который можно завернуть такие вещи.
Ну не скомпилируется у пользователей, сделают как надо, в чём проблема? Ну ещё можно #define NULL nullptr :). Если NULL используется правильно, то должно сработать.
Кому нужны паттерны STL, пусть используют её, причём здесь моя библиотека? При желании можно использовать обе библиотеки. Мой pair не подойдёт, пусть берут std::pair.
В смысле замену концептам? Это же фича языка, которую ещё не приняли. Как я могу выкатить её замену? И не очень понятно, зачем она такая громоздкая нужна вообще. Если для того, чтобы заменить SFINAE, то для этого лучше бы просто сделали if времени компиляции в прототипе функции, как в D, а не городили целый язык в языке.
Soul_re@ver 31.07.2016 19:07 # 0
Огромное количество компаний всё ещё живут в 80х. Компании, которые зачастую и являются основными клиентами. Если случится увидеть внутренности софта для банков, постарайся не спиться после этого. В общем, решаешь их проблемы ты. Иначе они идут к тому, кто их решает, а ты сидишь на пособии по безработице.
> Как я могу выкатить её замену?
http://www.boost.org/doc/libs/1_61_0/libs/concept_check/concept_check.htm
Концепты нужны не столько для SFINAE, сколько для выражения требований напрямую в коде, человекочитаемых ошибок и чтобы ошибка случилась на стадии проверки типа а не после раскрытия 500 уровня вложености шаблонов.
> Ну не скомпилируется у пользователей, сделают как надо
Я уже написал, как сделают: идёт нахуй после второй-третьей обнаруженной особенности и берётся нормальная.
В общем, как библиотека для себя она пойдёт неплохо, но для того, чтобы ей кто-то ещё стал пользоваться, придётся начать жить в реальном мире. У нас тоже код для внутреннего пользования не обязан работать с NULL, но интерфейс, который видят клиенты обязан корректно обрабатывать ситуацию, когда пошлют 0 вместо указателя. Потому что если это разрешено, это сделают. Гарантировано. А потом будут жаловаться что твоя либа сломалась. Или ты начнёшь в ответ отмазываться, что либа не работает когда у класса перегружен оператор&?
gammaker 31.07.2016 19:32 # 0
Ну SFINAE же оно и есть, разве нет? Если ни для одной перегрузки SFINAE не сработал, компилятор скажет, что нет подходящих перегрузок. Просто надо все условия в enable if прописать.
Из-за какого-то сраного 0\NULL? Это какая-то придирка на пустом месте. В STL я вообще могу написать std::string str = false. Это даже скомпилируется в студии, но программа упадёт в рантайме. А у меня всего лишь не скомпилируется 0, когда в документации например будет написано, что можно передавать null. Ну почитают документацию, напишут null, если сами не догадаются. Иногда некоторые сторонние библиотеки вообще глючат или не компилируются на пустом месте, но кто-то их всё-таки использует. А тут такая мелочь.
А вообще в чём вопрос с NULL? С перегрузкой int\указатель что ли? Если так, то у меня вроде таких перегрузок почти нет. Есть только там, где в принципе любое поведение может считаться корректным - например метод ToString для NULL вернёт 0, что в общем-то тоже норм.
Погоди, какой оператор &? А он тут откуда? Унарный, бинарный?
Кстати, а в моих строках ни string str = false, ни string str = 0 не компилируется, в отличие от STL. А string str = null или string str = (char*)0 компилируется и даёт пустую строку в отличие от STL, который просто приводит к падению программы.
Soul_re@ver 31.07.2016 20:11 # +1
Не можешь. Если получается — баг компилятора.
> А вообще в чём вопрос с NULL?
http://coliru.stacked-crooked.com/a/5f6e09025da39969
Это не придирка а наиболее простой вид неудобного поведения С++ в некоторых случаях. Другие труднее показать.
> Погоди, какой оператор &?
Унарный. Библиотека должна работать даже если он перегружен. Или явно выставлять требования к его поведению. А чем больше требований, тем хуже.
> string str = null или string str = (char*)0 компилируется и даёт пустую строку в отличие от STL, который просто приводит к падению программы.
А string str = (char*)1? И вообще какая строка хранится по адресу 0? Нет строки и пустая строка это разные вещи. STL здесь сделал правильно позволив инициализировать себя только из ВАЛИДНОЙ с-строки.
> Ну SFINAE же оно и есть, разве нет?
Нет. Концепты полезны вообще без всяких перегрузок.
Скажем
template <RandomAccess T>
void foo(T);
Выдаст с концептами что-то вроде error: MyIter does model RandomAccess: not Additive(MyIter, size_t), а без концептов что-то вроде error: in template ... in template <100 строк пропущено> couldn't find operator+ (operands are __DET__IterAdapter__1__p03<::mylib::hold er<MyIter, tag::12>> and size_t)
gammaker 31.07.2016 20:54 # 0
Ну очевидно же, что надо nullptr использовать. Уже сто лет прошло с тех пор, как он начал везде поддерживаться. А как в STL эту проблему решают?
А его (&) что так часто перегружают, что у моей библиотеки из-за этого сильно аудитория убавится? Кроме умных указателей вроде не встречал реальных применений.
У меня по семантике null, он же nullptr - показатель пустого объекта. А чтобы не было разницы в поведении между (char*)0 и null пришлось сделать так. Если передать (char*)1 или другой невалидный указатель, то естественно всё упадёт.
Ну так enable if с условием random access сделать и компилятор не полезет внутрь этой функции, а скажет, что инстанциация провалилась. С концептами конечно сообщение об ошибке было бы лучше, но для этого необязательно было придумывать громоздкие концепты, когда можно было бы сделать if как в D перед телом функции. Я уже об этом говорил.
Soul_re@ver 31.07.2016 21:24 # 0
Поздравляю, ты почти придумал концепты. Только проверить, валидна какая либо произвольная синтаксическая конструкция с помощью enable_if невозможно. А как в D с if решить эту проблему без огромной портянки проверяющей все условия?
> А как в STL эту проблему решают?
Убеждаясь, что NULL будет работать. Реально — SFINAE, вырубая данный конструктор, если бы он был бы невалиден.
gammaker 31.07.2016 21:42 # 0
В зачем портянки? Объединяешь все мелкие условия в одно большое заранее и только его проверяешь. Вот тут примеры: http://dlang.org/phobos/std_range.html#.Cycle
Soul_re@ver 31.07.2016 22:01 # 0
К тому же, не получится проверить наличия, скажем, оператора++. Как минимум провалится на встроеных типах
> Вот тут примеры
И чем это принципиально отличается от
или
gammaker 31.07.2016 22:21 # 0
Soul_re@ver 31.07.2016 22:33 # 0
Два слова: concept для объявления концепта и requires для inline-вычисления концепта (что-то вроде PARSING FAILURE IS NOT AN ERROR). В остальном это такие же булевы условия и да, действительно краткая запись условия "если вон та фигня компилируется и имее такой тип".
В D небось isForwardRange тоже весьма нетривиально определён.
gammaker 31.07.2016 22:51 # 0
Вот так в D сделано:
template isInputRange(R)
{
enum bool isInputRange = is(typeof(
(inout int = 0)
{
R r = R.init; // can define a range object
if (r.empty) {} // can test for empty
r.popFront(); // can invoke popFront()
auto h = r.front; // can get the front of the range
}));
}
isForwardRange определяется через isInputRange и там ещё одно условие проверяется. Видимо is(typeof((inout int = 0){...}))) в C++ надо заменить на void_t<decltype(...)> плюс ещё как-то из этого bool вытащить.
Soul_re@ver 31.07.2016 22:58 # 0
Может где-то {} лишние.
kurwa 31.07.2016 22:13 # 0
С enable_if нет. А вот если вместо enable_if сделать void_t<decltype(proizvolnaya sintaksicheskaya konstrukciya)>, то должно работать вроде. По крайней мере можно проверить возможность выполнения операций, наличие методов.
kurwa 31.07.2016 22:27 # 0
gammaker 31.07.2016 22:42 # 0
Если так, то пойду запиливать у себя. Говнокод оказывается бывает полезен :). Только надо придумать, как это в bool превратить.
kurwa 31.07.2016 22:48 # 0
kurwa 31.07.2016 22:54 # 0
http://en.cppreference.com/w/cpp/language/sfinae
Про этот трюк написано в секции Expression SFINAE. Все валидно.
gammaker 31.07.2016 22:56 # 0
gost 31.07.2016 20:17 # 0
А зачем тогда твой pair вообще нужен? Надо сразу брать std::pair и не усложнять себе жизнь.
gammaker 31.07.2016 20:57 # 0
gost 31.07.2016 23:31 # 0
PS, а <tuple> и <utility> миллиарды строк стандартной либы с собой не тащат?
gammaker 31.07.2016 23:40 # 0
Soul_re@ver 31.07.2016 23:51 # 0
gammaker 31.07.2016 23:55 # 0
Soul_re@ver 31.07.2016 23:56 # 0
gammaker 01.08.2016 00:04 # 0
Soul_re@ver 01.08.2016 00:08 # +2
Что, блядь? По-моему, это чья-та криворукость.
в типичном
template<typename... Types>
struct tuple : holder<Types>...
Всё по порядку. Хотя одна из фишек стандартного кортежа, это то что он имеет право переставлять поля для минимизации места.
gammaker 01.08.2016 00:18 # 0
А про множественное наследование даже и не подумал. Интересная идея. А почему так в STL не сделали? Да и вообще все в уроках по variadic templates изобретают рекурсивные кортежи.
А порядок наследования полей стандартом чётко определён? Всё будет по порядку и выравнивания будут неотличимы от аналогичной структуры?
Soul_re@ver 01.08.2016 00:27 # +1
Это где? Ни в libc++ ни в визуалке такой хуйни нет, там множественное наследование.
> А порядок наследования полей стандартом чётко определён?
Да. Сначала первый базовый класс, затем второй... Затем поля самого класса.
Вот пример туплоподобного класса, который будет в С++17 считаться аггрегатом и работать со structured bindings и guaranteed copy elision. Создан чтобы вообще без затрат вернуть несколько значений из функции:
http://melpon.org/wandbox/permlink/9NBqkcbOuURFvypt
Слегка недоделан (нужно ещё пару вариантов get добавить)
gammaker 01.08.2016 00:30 # 0
template<class _This,
class... _Rest>
class tuple<_This, _Rest...>
: private tuple<_Rest...>
{ // recursive tuple definition
...
А зачем нужен будет кортеж, если есть это many?
Soul_re@ver 01.08.2016 00:38 # 0
> А зачем нужен будет кортеж, если есть это many?
Технически его ещё нет. Оно нормально на текущем стандарте не заработает.
Плюс оно скорее всего не поддерживает ссылки, move-only типы и вообще это 90% кода тупла (минус конструкторы) и без оптимизаций размера.
gammaker 01.08.2016 00:43 # 0
Soul_re@ver 01.08.2016 00:47 # 0
kurwa 01.08.2016 00:00 # 0
Soul_re@ver 01.08.2016 00:06 # 0
Antervis 31.07.2016 16:18 # 0
А вообще, Qt занимателен не только за счет своих виджетов, из которых он вырос, но которые потихоньку уступают место QML. Там куча инструментов на все случаи жизни. В т.ч. и для сериализации/десериализации
gammaker 31.07.2016 16:36 # 0
Ну вот инструменты на все случаи жизни я и делаю сейчас. Не хватает самого главного - GUI. Ну ещё звук доработать и сеть добавить. Потом для распараллеливания циклов алгоритмов наделать ещё планирую.
bormand 31.07.2016 16:48 # 0
gammaker 31.07.2016 16:53 # 0
Dummy00001 01.08.2016 16:46 # 0
когда-то барьер для использования STL в Qt приложениях был высокий - но последний раз когда пробовал, я просто в лоб QList/QMap/QString/std::vector/std::map/std::string мешал, и все как-то загадочно скомпилировалось и работало.
Antervis 01.08.2016 18:38 # 0
Antervis 31.07.2016 20:31 # 0
gammaker 31.07.2016 21:18 # 0
Но разделённая память по-моему никакого отношения к move семантике не имеет. Там тогда надо будет пихать атомарные счётчики ссылок. И чтобы их дёргать реже как раз нужна move-семантика.
У них судя по всему shared memory сделана через shared_ptr<pimpl>. И ABI совместимость обеспечили и от лишних копирований избавились. Но зато лишнюю индирекцию получили.
Я из того обсуждения так и не понял, зачем QList. Что бы изменилось, если бы вместо него был std::vector? А аргументы функций, принимающих массивы, лучше вообще сделать не контейнерами, а чем-то вроде моего ArrayRange - удобной оболочкой над парой указателей.
Antervis 31.07.2016 22:04 # +1
> Что бы изменилось ...
Модификации типа сортировки/вставки/удаления для вектора больших элементов куда медленнее чем аналогичные операции с вектором указателей на объекты. Чем и является QList для элементов больше sizeof(void*)
gammaker 31.07.2016 22:30 # 0
А вот с элементами меньше void* ситуация как раз наоборот. Место транжирится зря.
Antervis 01.08.2016 14:52 # 0
Вот пришел к вам вчерашний студент в контору. Скажи ему написать что-то на бусте - на сотню постов сюда наберется. А на Qt - изи
Antervis 31.07.2016 20:40 # +1
gammaker 31.07.2016 21:20 # 0
Antervis 31.07.2016 21:55 # 0
noexcept(noexcept(func(declval<T>())))
gammaker 30.07.2016 23:44 # 0
И не вижу никакой алогичности. В продакшене бывают ужаснейшие говнокоды, которые здесь конечно же встречаются, и как-то живут.
CHayT 01.08.2016 18:36 # +3
В рамках филосовской регрессии: cpp -- это тоже внешний кодогенератор, только кривой и убогий.
gammaker 01.08.2016 18:42 # 0
CHayT 31.07.2016 00:24 # 0
gammaker 31.07.2016 00:55 # 0
Если у меня это не будет получаться, либо я захочу выложить свои наработки в открытый доступ для других, я наверное займусь реализацией поддержки указателей. А пока займусь другими делами.
CHayT 01.08.2016 18:46 # 0
А вот более-менее нетривиальные случаи приведут к говнокоду, багам и хуёвой производительности.
> в открытый доступ для других
Биндинги для других языков уже есть? Хотя бы спецификация формата и поддержка версионирования?
gammaker 01.08.2016 18:51 # 0
Ни биндингов, ни спецификации. Я же в первую очередь для себя делаю. Ещё даже не выкладывал свою либу.
Хотя в принципе спецификация проста - все POD'ы сериализуем как есть, остальное по порядку, массивы и строки - длина 4 байта + данные.
bormand 01.08.2016 17:30 # 0
З.Ы. Интересно, а множественное наследование эта либа понимает?
Soul_re@ver 01.08.2016 18:06 # +1
С виртуальным ещё интересней.
gammaker 01.08.2016 18:49 # 0
Можно конечно подумать и попробовать сделать остальное, но мне пока это не нужно, а я делаю только то, что мне нужно в ближайшее время. Если я возьмусь за всё сразу, то я ничего толкового сделать не успею.
bormand 01.08.2016 18:53 # 0
Нафиг? Просто родителей перечислить же. Ну и чтобы родители тоже были сериализуемыми.
gammaker 01.08.2016 19:52 # 0
bormand 01.08.2016 19:57 # 0
gammaker 01.08.2016 20:09 # 0
Другими словами, нужна штука типа такой:
type_exists<std::enable_if_t<false>>::va lue == false
type_exists<std::enable_if_t<true>>::val ue == true
Вот как её сделать?
Soul_re@ver 01.08.2016 20:16 # 0
bormand 01.08.2016 20:18 # 0
Soul_re@ver 01.08.2016 20:24 # +1
gammaker 01.08.2016 20:31 # 0
bormand 01.08.2016 20:32 # 0
gammaker 01.08.2016 20:40 # 0
bormand 01.08.2016 21:00 # 0
gammaker 01.08.2016 21:02 # 0
bormand 01.08.2016 21:03 # 0
Kozel 31.07.2016 06:24 # +1
rusML.FalseTrueNames[0] = "да";
bormand 31.07.2016 07:07 # −1
gammaker 31.07.2016 10:49 # 0
Ложь - это истина. Истина - ничто.
gammaker 31.07.2016 10:48 # 0
gost 31.07.2016 15:59 # 0
gammaker 31.07.2016 16:04 # +1
Bobik 31.07.2016 20:10 # +5
j123123 02.08.2016 01:45 # +1
kurwa 02.08.2016 10:31 # +1
j123123 02.08.2016 12:16 # +1
Допустим, какой-то мудень написал
И если эта поебень закодирована в 8-битной говнокодировке, типа windows-1251 или KOI8-R то если просто в лоб перекодировать эту поеботу в UTF-8 то будет некомпилируемая хуита. Если в этой строке закодированной в однобайтной говнокодировке меняет одну букву на другую
то эта поебень при конвертации в UTF-8 тоже сломается нахуй. Продолжать?
j123123 02.08.2016 12:22 # 0
Soul_re@ver 02.08.2016 12:25 # 0
Это про applocale? Оно же deprecated ещё с XP.
kurwa-nextgen 02.08.2016 14:02 # 0
А если я хочу писать комментарии на русском? А если я хочу использовать эмодзи в качестве идентификаторов? А если у меня файлы в утф-8 и мой код ищет на странице, скачанной из интернета подстроку "ソサイクダサイ" с помощью std::string::find, например? Почему это мне нельзя это делать?
Soul_re@ver 02.08.2016 14:36 # −1
> А если я хочу использовать эмодзи в качестве идентификаторов?
То ты мудак. У меня дикая ненависть к японцам из-за их любви использовать свой мунспик в идентификаторах. Из-за чего нормально локализовать некоторые вещи не получается и вообще ковыряться в коде — боль.
gammaker 02.08.2016 12:33 # 0
j123123 02.08.2016 12:34 # +2
guest 02.08.2016 12:37 # 0
dxd 02.08.2016 13:49 # +2
gammaker 02.08.2016 14:41 # +1
Под "все ОС" я имел в виду Linux\FreeBSD и подобные, которые даже на уровне стандартных библиотек C\C++ работают с UTF-8 по умолчанию, а также винду, на которой я тоже добился того, чтобы UTF-8 строки выводились на консоль, MessageBox, и вообще обрабатывались моей либой корректно. А стандартные либы я просто не использую.
Разве что иногда приходится следить, чтобы винда\студия не сохраняла исходники в CP1251. Но для этого у меня есть программа для преобразования кодировок файлов с нужным расширением в папке рекурсивно. Я запускаю её раз в несколько месяцев и иногда вижу там несколько файлов в CP1251, которые преобразуются в UTF-8.
bormand 02.08.2016 20:02 # 0
Т.е. всё это время вместо строк из этих файлов юзерам показывается какая-то левая хуйня?
gammaker 02.08.2016 20:14 # 0
j123123 02.08.2016 22:18 # 0
Это где ты в стандартной библиотеке C нашел функции для работы с юникодом? В плюсах-то они вполне могут быть в новых стандартах, хуй знает что там эти норкоманы нахуевертили
gammaker 02.08.2016 22:32 # 0
Soul_re@ver 02.08.2016 22:46 # +2
3_14dar 03.08.2016 01:21 # 0
kegdan 04.08.2016 10:40 # 0
Смотрите, типичный прыщедебил
Мухаха
dxd 04.08.2016 14:37 # +1
inkanus-gray 04.08.2016 14:53 # +1
gammaker 04.08.2016 14:55 # +1
А в винде видимо не хотели ломать обратную совместимость. Хотя могли бы хотя бы wcout научить без танцев с бубном выводить Юникодовые символы.
1024-- 04.08.2016 17:43 # 0
Если отойти от консолечки и оценить срачики, оказывается, что
1. С точки зрения пользователя А в системе А всё работает, а в системе Б ничего не работает, надо долго настраивать.
2. С точки зрения пользователя Б в системе Б всё работает, а в системе А ничего не работает, надо долго настраивать.
3. С точки зрения В в системах А и Б вообще абсолютно всё работает, а А и Б - ламеры и не умеют настраивать.
Разумеется, под словом "всё" понимается "всё, что нужно пользователю А/Б", а А и Б счастливы и выбрали ОС, идеально подходящую под их задачи, а В - неленивый.
Интересно, будет ли ОС, где А и Б смогут реально всё использовать без боли. Подойдёт ли на эту роль Windows 10 с экстрактом линукса?
3oJloTou_xyu 04.08.2016 20:15 # −1
Antervis 04.08.2016 20:40 # 0
Soul_re@ver 02.08.2016 22:33 # +2
Там пока рассматривается отдельные функции для ASCII текста, чтобы локали ПИРФОМАНС не убивали. УТФ8 дай бог в этом столетии появится.
bormand 02.08.2016 20:04 # +2
guestinho 02.08.2016 22:30 # +2
То ли дело php
bormand 02.08.2016 22:33 # +2
kegdan 05.08.2016 12:09 # +4
"- Я посмотрел твой код и нашел там неявный каст. Сымай штанишки"
inkanus-gray 05.08.2016 16:35 # +2