1. C++ / Говнокод #20449

    +1

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    24. 24
    25. 25
    26. 26
    27. 27
    28. 28
    29. 29
    30. 30
    31. 31
    32. 32
    33. 33
    34. 34
    35. 35
    36. 36
    37. 37
    38. 38
    39. 39
    40. 40
    41. 41
    42. 42
    43. 43
    44. 44
    45. 45
    46. 46
    47. 47
    48. 48
    49. 49
    50. 50
    51. 51
    52. 52
    53. 53
    54. 54
    55. 55
    56. 56
    57. 57
    58. 58
    59. 59
    60. 60
    61. 61
    62. 62
    63. 63
    64. 64
    65. 65
    66. 66
    67. 67
    68. 68
    69. 69
    70. 70
    71. 71
    72. 72
    73. 73
    74. 74
    75. 75
    76. 76
    77. 77
    78. 78
    79. 79
    80. 80
    81. 81
    82. 82
    83. 83
    84. 84
    85. 85
    86. 86
    87. 87
    88. 88
    89. 89
    90. 90
    91. 91
    92. 92
    93. 93
    94. 94
    95. 95
    96. 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

    Комментарии (173) RSS

    • Ещё два написанных сериализатора/десериализатора, и ты поймёшь, что кроме протобуфа ничего не нужно.
      Ответить
      • Зачем мне ещё два писать, если у меня уже есть сериализатор? Можно просто его развивать и всё. И вообще protobuf генерирует посторонний код, который нужно вкомпилировать в свой проект. Мне не нравится такой подход. Кроме того, protobuf - бинарный, а значит, его область применения отличается от того, что здесь выложено. И раз уж он бинарный, он должен поддерживать работу с данными, загруженными или даже замапенными из файла напрямую - без десериализации. Но он не умеет. правда у гугла есть flatbuffers, который умеет, но в остальном там те же недостатки.
        Бинарная десериализация у меня тоже есть, но там настраивать нечего, поэтому я решил, что выкладывать её сюда не так интересно будет.

        Вообще я собираюсь сделать универсальный бинарный формат, который будет содержать не только сами данные, но и саму структуру этих данных. То есть в нём будет указано, что в нём лежит, и можно будет найти и замапить нужный участок (если он POD) в память, и работать с ним, как с массивом структур. Если не POD, то придётся десериализовать, что будет происходить автоматически, как в этом коде.
        Ответить
        • >Зачем мне ещё два писать, если у меня уже есть сериализатор?
          Думаю, скоро выяснится, что для каких-то задач он плохо применяется.
          >Мне не нравится такой подход
          А макрос ADD_REFLECTION нравится?
          >Кроме того, protobuf - бинарный, а значит, его область применения отличается от того, что здесь выложено
          У proto3 него есть "canonical mapping" в json и "textformat", который несколько корявый. В целом, не любой формат, но жить можно.
          Кроме того, у всех сгенерированных структур есть дескрипторы, по которым дампер в любое текстовое представление пишется достаточно тривиально.
          >содержать не только сами данные, но и саму структуру этих данных
          Что, опять же, есть в протобуфе.
          >замапить нужный участок (если он POD) в память, и работать с ним, как с массивом структур
          То есть работать будет только на одной архитектуре?
          Ответить
          • > работать будет только на одной архитектуре
            Для многих применений этого достаточно, если файл предполагается читать на той же самой машине.
            Ответить
            • > Для многих применений этого достаточно, если файл предполагается читать на той же самой машине.

              reinterpret_cast<char[sizeof(MyStruct)]>?
              Ответить
          • Как он может плохо применяться, если он такой универсальный? Синтаксис, как тут уже показано, можно подстраивать как угодно. Скорость высокая. Особенно, если в релизе перегонять всё в бинарь, там скорость будет ещё выше - бинарная сериализация миллиона таких громоздких структур на моём ноуте длится всего 300 мс, а десериализация - 1300 мс. Текстовая десериализация уже потяжелее - 14 секунд.
            Есть некоторые вещи, которые ещё не реализованы, потому что мне не нужны, но я всё равно думаю, как бы я их реализовал, и вроде они просто и органично впишутся в тот сериализатор, который уже есть.

            Это всего лишь один макрос, вызов которого занимает одну строчку. Всё делается в коде без посторонних утилит. А когда в C++ добавят нормальную рефлексию, если такое когда-нибудь случится, можно будет и макрос убрать. Вроде собирались добавить в C++17, но передумали.
            Ответить
          • И вообще мой сериализатор позволил очень много всего унифицировать в моих проектах. То есть многие парсеры, которые я писал для чтения файлов моим движком, теперь реализуются с помощью десериализатора и отдельного кода, который обрабатывает готовые структуры и массивы. Весь парсинг, который представлял собой частные случаи того, что есть, можно теперь выкинуть, уменьшив количество кода, которое приходится поддерживать. Вывод структур в логе тоже упрощается. Просто сериализовал в удобный формат и записал. Не надо делать форматирование строк, кучу операторов вывода '<<' или кучу вызовов ToString.

            Протобуф может и содержит информацию о структуре, но по-любому требует пользоваться своими сгенеренными классами. Я ненавижу кодогенераторы и предпочитаю получать то, что я пишу сам на C++.

            Работать будет на всех архитектурах с одинаковой endianess и одинаковыми float'ами вроде как. То есть x86 + ARM уже можно охватить одной версией формата, а под другие архитектуры я во-первых писать не планирую пока, а во-вторых можно свои файлы сделать. Скорее всего у меня в движке будет компилятор, который автоматически будет переводить текстовые файлы в бинарные под нужную архитектуру, сжимать текстуры под нужную платформу и так далее.
            Ответить
            • > под другие архитектуры
              amd64 не поддерживаешь?
              Ответить
              • Поддерживаю. А с ним-то какие проблемы?
                Ответить
                • Ну если всякие size_t, long и т.п. в своих структурах не юзаешь - вроде нету.
                  Ответить
                  • long вообще не юзаю. size_t в основном в контейнерах, которые всё равно сериализуются не через рефлексию, а по-своему.

                    А моему будущему сериализатору универсального формата будет вообще пофиг на разницу между short, int и long long. Он будет знать всё о типах с обеих сторон и автоматически приведёт тип.
                    Ответить
                    • > автоматически приведёт тип
                      А если не влезает?
                      Ответить
                      • Тогда произойдёт усечение, и загрузчик ругнётся в лог об этом инциденте.
                        Ответить
                        • > усечение
                          С насыщением до максимума или тупо старшие биты отвалятся?

                          З.Ы. Лог логом, но я бы всё-таки ошибку загрузки вернул, чтобы потом косяки не полезли.
                          Ответить
                          • Как сделаешь, так и будет. Десериализатору доступна вся информация о типах и он может делать как хочешь. Я наверное сделаю с насыщением.

                            Если лог не пустой, значит ошибка. Никаких дополнительных кодов ошибки не нужно, а исключения я не использую. Лог не глобальный, он не пишется в файл. Он локальный для десериализатора и пишется в строку. То есть если пользователю пофиг на ошибки, он не будет смотреть лог и не узнает о них. Если не пофиг, он выведет лог на консоль, в MessageBox или ещё куда-нибудь, например в глобальный лог-файл. А если пользователь не хочет допускать вообще никаких ошибок, он выдаст ошибку и завершит программу. Вот например:

                            deserializer.Deserialize<SuperTest>();
                            if(deserializer.Log!=null) Console.PrintLine("При десериализации произошли следующие ошибки:", endl, deserializer.Log);
                            Ответить
        • > который будет содержать не только сами данные, но и саму структуру этих данных

          Воооот. Вот это дело. Не скупись на метаданные, а то не распарсится ничего.
          Ответить
          • Вот я и собираюсь сделать полноценную систему типов в файле. Причём тип будет в то же время являться и значением - его можно будет класть в поле структуры и в массивы. Таким образом, формат может быть использован абсолютно для любых целей: хранение моделей, текстур, конфигов, строк для локализации, сцен. Если формат файла незначительно изменился, например было удалено или добавлено необязательное поле, а программа осталась старая, то она просто проигнорирует лишнее поле, а вместо удалённого подставит его значение по умолчанию. И аналогично с новой программой и старым файлом. Поле с изменившимся типом будет каститься в случаях, когда такой каст возможен. И всё будет работать без необходимости на каждый чих перестраивать все файлы и код их сохранения\загрузки.
            Ответить
          • > Не скупись на метаданные, а то не распарсится ничего.
            Опять метушня? Опять метушня.
            Ответить
        • > замапить нужный участок (если он POD) в память, и работать с ним, как с массивом структур

          В Я нечто похожее используется — называется MMS. Только там метаданные не хранятся — уж больно накладно получается.

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

          Эта технология используется, например, для доставки здоровенных графов на сервера. Т.е. некий процесс создаёт в памяти граф и сериализует его, сериализованный файл торрентом заливается на тучу машин, после чего кластер синхронно и переключается на новую версию графа с минимальными задержками.

          Если интересно — посмотри видео, почитай сорцы.
          https://events.yandex.ru/lib/talks/1934/
          https://github.com/yandex/mms
          Ответить
          • Метаданные по идее должны весить 0,1% от самих данных, если масштабы достаточно большие. Это же описание структуры, а затем большой массив таких структур. В чём накладность?

            Не понял, как можно мапить не-POD данные из файла. Ну ладно, завтра посмотрю, почитаю.
            Ответить
            • > Метаданные по идее должны весить 0,1% от самих данных, если масштабы достаточно большие.

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

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

              Предположим, мы сериализуем его в какой-нибудь BSON, который для каждого значения хранит тип. Имеем "массив массивов интов", при этом для каждого инта в каждом массиве мы храним ещё один инт ­— метку типа "следующее значение — int".
              В итоге оверхед как минимум 100%.

              Если у нас в системе рантайм-типов есть метка "следующее значение — массив интов". Тогда у нас хранится один "универсальный массив" + N "массивов интов". Оверхед стал меньше — примерно 100 / K %.
              Ответить
              • Вот потому я и не взял BSON, а решил делать свой универсальный формат. Базой для этого формата будет моя сериализация.

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

                Недостатков у этого метода по-моему вообще нет, если не считать сложность реализации. Файлы весят мало, доступ самый быстрый, версионирование и расширяемость на высоте, автоматическая десериализация.

                Сейчас пока только есть письменное описание формата - где какие байты в каком порядке идут и что обозначают. Собираюсь скоро начать реализовывать его на базе своей уже реализованной сериализации.
                Ответить
                • Ещё чуть-чуть, и вы изобретёте схемы.
                  Ответить
                  • Большую часть всего этого я придумал, прочитав это:

                    https://blog.molecular-matters.com/2014/02/21/schema-based-entity-component-data-for-fast-iteration-times/

                    Ведь эти схемы имелись в виду или какие-то другие?

                    Я сначала хотел повторить это у себя, а потом понял, что можно сделать лучше и устранить многие недостатки. Думал, думал, и в итоге пришёл вот к этой сериализации и универсальному формату.
                    Ответить
    • > ArrayRange<char>(charBuf, 5000)
      > 5000
      А дефолта на весь массив нету что ли? Неудобно же указывать размер каждый раз. И ведь по-любому 90% кода оборачивает массив целиком.

      > char
      Ну и вывод типа разве не пригодился бы?
      Ответить
      • Есть, можно не указывать. Но я зачем-то указал. Не знаю, зачем я это сделал.
        Ответить
    • о, ламповая рефлексия на макросах, ее наверно каждый 2ой крестовик делал
      Ответить
      • Что-то не встречал нигде подобных реализаций, хотя я вроде искал библиотеки для сериализации, читал их сравнения. Большинство из таких библиотек сериализации вообще ручные были, то есть автоматически ничего не сериализовали. Только в бусте вроде есть REFLECTABLE, но там сами поля приходится через него объявлять. Intellisense не очень с этим вроде дружит.

        Да и вообще вариативные шаблоны - это то ещё извращение. Вряд ли каждый второй крестовик дорос до их использования.
        Ответить
        • > Вряд ли каждый второй крестовик дорос до их использования.
          лол
          Ответить
          • Я опечатался - не вариативные шаблоны, а вариативные макросы.

            Ты правда уверен, что каждый второй крестовик дорос до этого:
            http://www.cyberforum.ru/cpp-beginners/thread1658956.html
            ?
            Ответить
            • > дорос
              И не перерос, спрыгнув на boost::preprocessor, который всяко удобней, чем голая макросня.

              Там тебе и вертикальное и горизонтальное раскрытие, и функциональщина типа map/filter, и простенькая арифметика...
              Ответить
            • Нецелесообразно использовать стандартный сишный препроцессор сложных случаях. Когда мне надо было нагенерить сотни сишного кода по шаблону (надо было перебрать все кобенации функций для старой кудовской железки, не поддерживающей указатели на функции), я просто запилил генератор на Haskell и language-c-quote.
              Ответить
        • boost::fusion смотрел?
          Ответить
          • Так он вроде для работы с типами на шаблонах, а я про макросы. Правда я опечатался в предыдущем посте.
            Ответить
        • тут даже не в реализации дело, а скорее в самой идее изобретать эту рефлексию, я такое раз 5 видел (не каких то готовых библиотек, а именно чьих то поделий созданных от желания велосипедить/нечего делать), если не больше
          ну правда, да, по-моему объявления в одну строчку нигде не было

          а вообще без твоих сырцов конечно не сказать, но имхо, там и в реализации сильно разгуляться негде: маппер юзающий указатели на члены классов + специальные структуры, макросами собственно и создаваемые, складывающиеся в статический ридонли контейнер внутри класса
          Ответить
          • Изобретаю рефлексию я потому, что по различным соображениям не использую STL, Boost и другие сторонние библиотеки.
            Я раньше сериализацию делал кортежем указателей на члены, но потом переделал на visitor. С ним короче и вариадик шаблонов не надо. Просто в ADD_REFLECTION добавился метод VisitEachField, а проект, где используется ADD_REFLECTION, даже трогать не надо.
            Статический read only контейнер - это просто static const ReflectionField[] массив внутри функции, который возвращается как ArrayRange<const ReflectionField> - пара указателей со всякими удобными методами.
            Там ещё перегрузка макросов, которой как бы нет в C\C++, но которую можно реализовать через *опу.
            Ответить
            • > кортежем указателей на члены, но потом переделал на visitor
              > это просто static const ReflectionField[]
              > пара указателей со всякими удобными методами.

              ну в общих чертах я примерно так себе и представляю

              > Там ещё перегрузка макросов, которой как бы нет в C\C++, но которую можно реализовать через *опу.

              с макросами можно делать много всяких извращений, было бы желание и время

              > что по различным соображениям не использую STL, Boost и другие сторонние библиотеки

              это на самом деле идеализм, не мне тебя учить, но вот когда ты хочешь переписать прям все все все - это плохо, бусты/етц не осиливаются в одно жало, есть неплохой такой шанс разочароваться
              Ответить
              • Разочароваться в чём? В том что я не могу переписать буст целиком? Мне это и не надо, я пишу только то, что нужно в данный момент. Вот если мне нужно что-то, что есть в бусте, но нет у меня, тогдада,мне приходится делать это самому. Но как правило на это уходит меньше дня, хотя на кое-что ушла неделя - диапазоны, как в D. В бусте они тоже есть, но по сравнению с D какие-то урезанные и неудобные. А я делал именно как в D.
                Ответить
                • > А я делал именно как в D.

                  ок, а почему тогда просто не использовать D? удерживают существующие проекты?
                  Ответить
                  • Во-первых там нет нормальных IDE. Семантической подсветки синтаксиса нет нигде. А я к ней привык и жить без неё не могу. Во многих IDE возникают всякие проблемы. Самой удобной IDE из существующих мне показался Eclipse DDT, но там отладка не работает, да и семантической подсветки не хватает, которая есть в том же CDT.

                    Во-вторых, там просто катастрофически разрастается бинарник. Меня категорически не устраивает, когда приложение чуть сложнее Hello World'а начинает весить полмегабайта. Многим на это пофиг, но не мне. У меня целый синтезатор midi на C++ весит всего лишь 57 КБ.

                    В-третьих, поддержка Android. До недавнего времени её не было, но вроде пишут, что появилась тестовая поддержка. Пока сыро, с этим связываться не хочется, но видимо скоро этот недостаток будет полностью устранён.

                    Ну и в-третьих да, у меня уже очень много всего написано на C++. Я уже не представляю свою жизнь без своих удобных велосипедов, поэтому и их тоже надо будет переводить на D, по крайней мере половину из них. Если бы в D не было всех вышеперечисленных недостатков, я бы наверное переписал свои проекты на него. А так переписывать 20000-30000 строк кода, зная, что придётся смириться с проблемами, которых нет сейчас, не хочется.

                    Вместо того, чтобы решать все эти проблемы, проще перенести все нужные фичи из D в C++.
                    Ответить
                    • > Во-первых там нет нормальных IDE. Семантической подсветки синтаксиса нет нигде
                      Современные IDE (особенно говновизуальная студия) являются просто дичайшим говном и должны быть выброшены нахуй вместе с этими уродскими плюсами.

                      https://www.youtube.com/watch?v=N8elxpSu9pw лучше бери пример с этого чувака
                      Ответить
            • > по различным соображениям не использую STL, Boost и другие сторонние библиотеки
              >> STL, Boost и другие сторонние библиотеки
              Лол.
              Ответить
              • Надо было запятую после "другие" поставить наверное.
                Ответить
    • Такое чувство, что на каком-то этапе становления каждый программист пишет свой сериализатор/десериализатор с преферансом и барышнями, после чего переходит на готовые решения.

      А вообще, сдается мне, что код не должен одновременно быть и в продакшене, и на сайте говнокода. Это алогично
      Ответить
      • Как же не пробежаться по полю с граблями. Эмпирический опыт же самый полезный.
        Ответить
        • >> Эмпирический опыт же самый полезный.

          Я вообще отрицаю любой другой опыт. Слова только все путают
          Ответить
          • > Я вообще отрицаю любой другой опыт.
            Солнце крутится вокруг земли, а земля - диск?
            Ответить
            • Как говорил Шерлок, мать его, Холмс: - Это, конечно, здорово, но для меня абсолютно бесполезно

              Кстати солнце крутится вокруг земли и существуют системы отсчета в которых земля - диск
              Ответить
          • как говорится: "дураки учатся на своих ошибках, мудрые - на чужих"
            Ответить
            • Все люди разные, и у каждого свой путь. Если для большинства изобретение велосипедов - ошибка, то для меня это призвание. Моя цель - сделать библиотеку уровня Qt, но при этом занимающую в 50 раз меньше места на диске как в бинарном виде, так и в количестве строк кода.

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

              Лично я ни разу не пожалел, что изобретаю велосипеды. Благодаря этому я отлично знаю C++. Мои велики самые быстрые, компактные, удобные и в то же время универсальные. Это не те велосипеды с квадратными колёсами, которые делают начинающие разработчики.
              Ответить
              • Фига ты отец.
                Ответить
                • Покоя не было от вас?
                  Не вы ли о Царе мне уши прошумели?
                  Вам дан был Царь?— так тот был слишком тих:
                  Вы взбунтовались в вашей луже,
                  Другой вам дан — так этот очень лих:
                  Живите ж с ним, чтоб не было вам хуже!
                  Ответить
              • библиотеку уровня Qt в одного не напишешь, тем более в свободное время.

                Что до строк кода и объема - тут есть момент, не спорю. Впрочем, многие вещи типа QPair/QFunction и пр. могли бы заменить на стандартные версии
                Ответить
                • В ближайшее время хочу хотя бы GUI сделать, ведь это по-моему самая распространённая причина делать на Qt. Для C++ как-то нет особо хороших кроссплатформенных и в то же время компактных GUI библиотек.

                  QPair и QFunction - это капля в море кода. По крайней мере у меня их аналоги занимают очень малую долю от всего кода.
                  Ответить
                  • А аналог pair поддерживает perfect forwarding? А пару указателей инициализировать NULL возможно?
                    Ответить
                    • Мне всегда хватало вот такого:
                      template<typename T1, typename T2> struct pair
                      {
                      T1 first;
                      T2 second;
                      };
                      По идее все конструкторы и операторы присваивания компилятор сам сгенерирует. Что в таком случае помешает perfect forwarding'у?
                      pair использую только как затычку, когда лень создавать структуру из двух полей, но нужно пропихивать элементы парами. Но в дальнейшем обычно находится, чем эти затычки заменить, и pair становится ненужным.

                      Для пары указателей на начало и конец у меня специальный класс ArrayRange, который как раз специально для этого предназначен и очень удобен в использовании.
                      Ответить
                      • Я хочу поиграть в игру.
                        http://coliru.stacked-crooked.com/a/147065d2d33d3550

                        Заставь пару <immovable_stone, immovable_stone> работать.

                        *Насчёт искуственности: многие вещи неперемещаемы после инициализации, вроде мютексов, тасков и прочей хуйни.
                        Ответить
                        • http://coliru.stacked-crooked.com/a/f66c9b2d04358d04

                          Я не уверен, что пихать мьютексы и таски в пары - хорошая идея.
                          Ответить
                          • А теперь возьми пару <int*, int*> и проинициализируй оба элемента 0. Не nullptr, а 0, как int* p = 0;

                            Плюс я не уверен, что если бы там не было более сложных типов, то не вызвались бы лишние конструкторы.

                            Ну и ещё где "не использую STL"? Использовать обобщённую пару, чтобы сделать пару это читерство.

                            В общем, как поковыряешься с такими проблемами, начинаешь понимать, почему в стандартной библиотеке столько кода. И начинаешь ненавидеть NULL.
                            Ответить
                            • Нулл то причем? Ненавидь Страуструпа и кресты.
                              Ответить
                            • А зачем 0? Сто лет уже не инициализировал указатели в 0 или NULL - только null. nullptr тоже слишком длинный, поэтому я у себя сделал просто null того же типа nullptr_t. К тому же null по смыслу больше подходит как инициализатор по умолчанию для различных объектов-не-указателей.

                              У меня свои кортежи есть. Там правда нет пока integer_sequence. Я думаю вообще избавиться от этих pair, которые всё равно используются в 2,5 мест, а заменить их на кортежи.

                              А зачем NULL ненавидеть? Просто не надо его использовать и всё.

                              Я у себя просто не допускаю таких проблем. У меня все объекты перемещаемы и имеют конструктор по умолчанию.
                              Ответить
                              • > А зачем 0

                                Стандарт разрешает, я хочу. И вообще у нас стандарт написания кода с 1988 г. не менялся, только дополнялся.

                                > У меня все объекты перемещаемы и имеют конструктор по умолчанию.

                                А если у объекта в принципе нет логичного значения по умолчанию? Two-stage initialization это дикий зашквар. Некоторые объекты типа атомиков не перемещаемые в принципе. И никах их перемещаемыми не сделать.

                                > А зачем NULL ненавидеть? Просто не надо его использовать и всё.

                                Я бы рад, но есть пользователи... Смотри п.1


                                В общем, если ты пишешь general-purpose библиотеку, то делать её совместимой со всеми существующими и ещё не существующими паттернами разработки придётся. Иначе библиотека идёт нахуй после второй-третьей обнаруженной особенности и берётся нормальная.

                                Специализированные библиотеки могут чхать на это так как они и так работают в ограниченном множестве случаев.

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

                                  У меня практически всё перемещаемо. Я специально так делаю, чтобы не было проблем с контейнерами и т.п.. Вроде всегда логичное значение находилось - пустой объект, который не содержит в себе никакого ресурса.

                                  Правда я потом столкнулся с тем, что лямбды оказались неприсваемыми и сделал optional, в который можно завернуть такие вещи.

                                  Ну не скомпилируется у пользователей, сделают как надо, в чём проблема? Ну ещё можно #define NULL nullptr :). Если NULL используется правильно, то должно сработать.

                                  Кому нужны паттерны STL, пусть используют её, причём здесь моя библиотека? При желании можно использовать обе библиотеки. Мой pair не подойдёт, пусть берут std::pair.

                                  В смысле замену концептам? Это же фича языка, которую ещё не приняли. Как я могу выкатить её замену? И не очень понятно, зачем она такая громоздкая нужна вообще. Если для того, чтобы заменить SFINAE, то для этого лучше бы просто сделали if времени компиляции в прототипе функции, как в D, а не городили целый язык в языке.
                                  Ответить
                                  • > Ну хочешь себе проблем, получай и решай их сам.

                                    Огромное количество компаний всё ещё живут в 80х. Компании, которые зачастую и являются основными клиентами. Если случится увидеть внутренности софта для банков, постарайся не спиться после этого. В общем, решаешь их проблемы ты. Иначе они идут к тому, кто их решает, а ты сидишь на пособии по безработице.

                                    > Как я могу выкатить её замену?

                                    http://www.boost.org/doc/libs/1_61_0/libs/concept_check/concept_check.htm

                                    Концепты нужны не столько для SFINAE, сколько для выражения требований напрямую в коде, человекочитаемых ошибок и чтобы ошибка случилась на стадии проверки типа а не после раскрытия 500 уровня вложености шаблонов.

                                    > Ну не скомпилируется у пользователей, сделают как надо

                                    Я уже написал, как сделают: идёт нахуй после второй-третьей обнаруженной особенности и берётся нормальная.

                                    В общем, как библиотека для себя она пойдёт неплохо, но для того, чтобы ей кто-то ещё стал пользоваться, придётся начать жить в реальном мире. У нас тоже код для внутреннего пользования не обязан работать с NULL, но интерфейс, который видят клиенты обязан корректно обрабатывать ситуацию, когда пошлют 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, который просто приводит к падению программы.
                                      Ответить
                                      • > В STL я вообще могу написать std::string str = false

                                        Не можешь. Если получается — баг компилятора.

                                        > А вообще в чём вопрос с 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)
                                        Ответить
                                        • >Это не придирка а наиболее простой вид неудобного поведения С++ в некоторых случаях.

                                          Ну очевидно же, что надо nullptr использовать. Уже сто лет прошло с тех пор, как он начал везде поддерживаться. А как в STL эту проблему решают?

                                          А его (&) что так часто перегружают, что у моей библиотеки из-за этого сильно аудитория убавится? Кроме умных указателей вроде не встречал реальных применений.

                                          У меня по семантике null, он же nullptr - показатель пустого объекта. А чтобы не было разницы в поведении между (char*)0 и null пришлось сделать так. Если передать (char*)1 или другой невалидный указатель, то естественно всё упадёт.

                                          Ну так enable if с условием random access сделать и компилятор не полезет внутрь этой функции, а скажет, что инстанциация провалилась. С концептами конечно сообщение об ошибке было бы лучше, но для этого необязательно было придумывать громоздкие концепты, когда можно было бы сделать if как в D перед телом функции. Я уже об этом говорил.
                                          Ответить
                                          • > Ну так enable if с условием random access сделать

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

                                            > А как в STL эту проблему решают?

                                            Убеждаясь, что NULL будет работать. Реально — SFINAE, вырубая данный конструктор, если бы он был бы невалиден.
                                            Ответить
                                            • В C++ есть шаблонномагические способы проверить наличие метода или типа в классе. Их нет в type_traits, нужно писать самому. Не знаю, может в бусте ещё есть. Только с операторами такое к сожалению не прокатывает.

                                              В зачем портянки? Объединяешь все мелкие условия в одно большое заранее и только его проверяешь. Вот тут примеры: http://dlang.org/phobos/std_range.html#.Cycle
                                              Ответить
                                              • Нужно генерировать специально для каждой функции. В бусте есть макро для регистрации функций.

                                                К тому же, не получится проверить наличия, скажем, оператора++. Как минимум провалится на встроеных типах

                                                > Вот тут примеры

                                                И чем это принципиально отличается от
                                                template <typename T>
                                                requires ForwardRange<T> && !Infinite<T>
                                                void foo(T)

                                                или
                                                void bar(RandomAccess it)
                                                Ответить
                                                • Тем, что в D все эти условия - просто шаблонная булевая переменная, а в C++ хотят добавить целый язык концептов с кучей ключевых слов вместо обычного ифа как в D. Шаблонные булевые переменные уже добавили в C++14, и для реализации того, что в D осталось лишь добавить возможность нормальной проверки условия и всё, даже новые ключевые слова не надо вводить.
                                                  Ответить
                                                  • > целый язык концептов с кучей ключевых слов

                                                    Два слова: concept для объявления концепта и requires для inline-вычисления концепта (что-то вроде PARSING FAILURE IS NOT AN ERROR). В остальном это такие же булевы условия и да, действительно краткая запись условия "если вон та фигня компилируется и имее такой тип".

                                                    В D небось isForwardRange тоже весьма нетривиально определён.
                                                    Ответить
                                                    • А откуда тогда в концептах такая большая техническая спецификация?

                                                      Вот так в 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 вытащить.
                                                      Ответить
                                                      • Насколько я понял, в концептах будет как-то так (Точно в синтаксе не уверен)

                                                        template<typename T>
                                                        concept bool isInputRange = requires(T x) {
                                                            { T a };
                                                            { x.empty } -> bool;
                                                            { x.popFront() };
                                                            { r.front };
                                                        };
                                                        Может где-то {} лишние.
                                                        Ответить
                                            • > проверить, валидна какая либо произвольная синтаксическая конструкция с помощью enable_if невозможно
                                              С enable_if нет. А вот если вместо enable_if сделать void_t<decltype(proizvolnaya sintaksicheskaya konstrukciya)>, то должно работать вроде. По крайней мере можно проверить возможность выполнения операций, наличие методов.
                                              Ответить
                                              • Вот http://ideone.com/0lD6aU
                                                Ответить
                                                • Ух ты, круто! Это на всех компиляторах с decltype, using, trailing return type и вариадиками работает?
                                                  Если так, то пойду запиливать у себя. Говнокод оказывается бывает полезен :). Только надо придумать, как это в bool превратить.
                                                  Ответить
                                                  • Не уверен на счет соответствия стандарту и разбираться лень. У меня на гцц и шланге работает.
                                                    Ответить
                                                    • Таки почитал.
                                                      http://en.cppreference.com/w/cpp/language/sfinae
                                                      Про этот трюк написано в секции Expression SFINAE. Все валидно.
                                                      Ответить
                                                    • Проверил в студиях 2013 и 2015 - работает в обеих.
                                                      Ответить
                                  • > Мой pair не подойдёт, пусть берут std::pair
                                    А зачем тогда твой pair вообще нужен? Надо сразу брать std::pair и не усложнять себе жизнь.
                                    Ответить
                                    • Сначала я его и брал, а потом решил заменить его своим, чтобы избавиться от инклюдов стандартной библиотеки, которые тянут десятки тысяч строк кода, которые компилятору потом отбрасывать придётся. Таким образом я ускоряю компиляцию.
                                      Ответить
                                      • И на сколько миллисекунд ускоряется компиляция без <pair>?

                                        PS, а <tuple> и <utility> миллиарды строк стандартной либы с собой не тащат?
                                        Ответить
                                        • У меня свои tuple и всё остальное. Я вообще не включаю ни одного стандартного хидера ни в одном из своих заголовочных файлов.
                                          Ответить
                                          • Тест на говно: как реализован кортеж, множественным наследованием или рекурсивным наследованием?
                                            Ответить
                                            • Ни так, ни так. У тебя осталась последняя попытка, чтобы угадать.
                                              Ответить
                                              • Неужели рекурсивной композицией?
                                                Ответить
                                                • Да, а что? Наследование меня не устроило тем, что там поля хранятся в обратном порядке. Правда композиция, как потом оказалось, всё равно не всегда обеспечивает совпадение расположения полей с полями соответствующей структуры, поэтому в принципе пофиг как делать.
                                                  Ответить
                                                  • > Наследование меня не устроило тем, что там поля хранятся в обратном порядке

                                                    Что, блядь? По-моему, это чья-та криворукость.

                                                    в типичном

                                                    template<typename... Types>
                                                    struct tuple : holder<Types>...
                                                    Всё по порядку. Хотя одна из фишек стандартного кортежа, это то что он имеет право переставлять поля для минимизации места.
                                                    Ответить
                                                    • Ну в STL они как раз перевёрнутые. Они там реализованы через рекурсивное наследование от следующей части кортежа.

                                                      А про множественное наследование даже и не подумал. Интересная идея. А почему так в STL не сделали? Да и вообще все в уроках по variadic templates изобретают рекурсивные кортежи.

                                                      А порядок наследования полей стандартом чётко определён? Всё будет по порядку и выравнивания будут неотличимы от аналогичной структуры?
                                                      Ответить
                                                      • > Они там реализованы через рекурсивное наследование от следующей части кортежа

                                                        Это где? Ни в libc++ ни в визуалке такой хуйни нет, там множественное наследование.

                                                        > А порядок наследования полей стандартом чётко определён?

                                                        Да. Сначала первый базовый класс, затем второй... Затем поля самого класса.

                                                        Вот пример туплоподобного класса, который будет в С++17 считаться аггрегатом и работать со structured bindings и guaranteed copy elision. Создан чтобы вообще без затрат вернуть несколько значений из функции:
                                                        http://melpon.org/wandbox/permlink/9NBqkcbOuURFvypt
                                                        Слегка недоделан (нужно ещё пару вариантов get добавить)
                                                        Ответить
                                                        • В визуалке 2015, вот скопировал оттуда:

                                                          template<class _This,
                                                          class... _Rest>
                                                          class tuple<_This, _Rest...>
                                                          : private tuple<_Rest...>
                                                          { // recursive tuple definition
                                                          ...

                                                          А зачем нужен будет кортеж, если есть это many?
                                                          Ответить
                                                          • Хм. Странно. STL столько говорил про переписаный кортеж и новую реализацию... Может просто не релизнули эти изменения.

                                                            > А зачем нужен будет кортеж, если есть это many?

                                                            Технически его ещё нет. Оно нормально на текущем стандарте не заработает.

                                                            Плюс оно скорее всего не поддерживает ссылки, move-only типы и вообще это 90% кода тупла (минус конструкторы) и без оптимизаций размера.
                                                            Ответить
                                                            • Я имею в виду потом, когда выйдет C++17 и обретёт широкую поддержку, нужен ли будет tuple вообще? Или будет уже два тупла и с ними придётся жить?
                                                              Ответить
                                                              • Ну этого many в стандарте нет. И вообще он служит ровно одной цели: инициализировать несколько переменных вызовом одной функции. На большее я его не затачивал. Если бы это не ломало аггрегатность, я бы вообще копировать и перемещать его бы запретил
                                                                Ответить
                                            • А какая разница?
                                              Ответить
                                              • Рекурсивные версии компилируется медленей, get<n> сложнее реализовать, и во многих случаях оно с линейной сложностью. Также EBO не работает и не сделать оптимизацию паддинга базовых классов.
                                                Ответить
                  • Дело не в том, капля или нет. Дело в дублировании кода, которого в общем случае лучше избегать.

                    А вообще, Qt занимателен не только за счет своих виджетов, из которых он вырос, но которые потихоньку уступают место QML. Там куча инструментов на все случаи жизни. В т.ч. и для сериализации/десериализации
                    Ответить
                    • Ну видимо они избегают использования STL, и делают как и я всё своё. Гораздо более непонятно,зачем они делали свои QVector и QLinkedList, когда в STL более универсальные аналоги. Чем они лучше? А QList у них вообще непонятно зачем нужен. Это как QVector, только с кучей недостатков сверху.

                      Ну вот инструменты на все случаи жизни я и делаю сейчас. Не хватает самого главного - GUI. Ну ещё звук доработать и сеть добавить. Потом для распараллеливания циклов алгоритмов наделать ещё планирую.
                      Ответить
                      • Вроде как они начинали всё это делать когда STL было корявым говном, стандарта c++98 ещё не было, а boost только-только собирался родиться...
                        Ответить
                        • Могли бы уже 10 раз переделать с тех пор.
                          Ответить
                          • Qt во многих местах поддерживает inter-operability c STL.

                            когда-то барьер для использования STL в Qt приложениях был высокий - но последний раз когда пробовал, я просто в лоб QList/QMap/QString/std::vector/std::map/std::string мешал, и все как-то загадочно скомпилировалось и работало.
                            Ответить
                          • думаю, когда ренджи примут они переделают малех контейнеры. По крайней мере я вижу в этом логику.
                            Ответить
                      • QList более-менее универсален и мы это уже обсуждали. Общая особенность контейнеров в Qt - shared memory. Это почти мув семантика в 98-м году!
                        Ответить
                        • Как будто move-семантика - это что-то такое выдающееся. Наверняка её можно было эмулировать, а если и не нельзя, то хотя бы сделать функцию move с двумя аргументами.

                          Но разделённая память по-моему никакого отношения к move семантике не имеет. Там тогда надо будет пихать атомарные счётчики ссылок. И чтобы их дёргать реже как раз нужна move-семантика.

                          У них судя по всему shared memory сделана через shared_ptr<pimpl>. И ABI совместимость обеспечили и от лишних копирований избавились. Но зато лишнюю индирекцию получили.

                          Я из того обсуждения так и не понял, зачем QList. Что бы изменилось, если бы вместо него был std::vector? А аргументы функций, принимающих массивы, лучше вообще сделать не контейнерами, а чем-то вроде моего ArrayRange - удобной оболочкой над парой указателей.
                          Ответить
                          • Контейнеры Qt reentrant а не thread-safe.
                            > Что бы изменилось ...
                            Модификации типа сортировки/вставки/удаления для вектора больших элементов куда медленнее чем аналогичные операции с вектором указателей на объекты. Чем и является QList для элементов больше sizeof(void*)
                            Ответить
                            • Это нужны объекты во много больше раз указателя, а то индирекция сведёт на нет весь профит. Для сортировки можно завести отдельный массив индексов\указателей и сортировать их, и не нужен никакой QList. А то он небось ещё каждый элемент в куче индивидуально выделяет? Или они это хотя бы додумались оптимизировать?

                              А вот с элементами меньше void* ситуация как раз наоборот. Место транжирится зря.
                              Ответить
                              • В Qt везде индирекция. И в целом там на спичках не экономят. В итоге один фиг достаточно быстро для 99.9% практических задач. Но в то же время достаточно просто.

                                Вот пришел к вам вчерашний студент в контору. Скажи ему написать что-то на бусте - на сотню постов сюда наберется. А на Qt - изи
                                Ответить
                      • п.с. жаль только что Qt сейчас не вводят модерновые фичи типа мув-семантики, emplace_back, повсеместного noexcept (с учетом того, что в Qt исключения не используются, ими можно покрыть 50% функций). Ну и конструкторы из двух итераторов таки нужны
                        Ответить
                        • Я тоже не использую исключения и noexcept. Я не понял, чем он отличается от старого throw(), да и вообще зачем нужен. Только если для оптимизации компилятором, но исключения и так у меня в настройках выключены.
                          Ответить
                          • noexcept отличается от throw() тем, что noexcept может быть условным:
                            noexcept(noexcept(func(declval<T>())))
                            Ответить
      • Ткните носом в готовое решение без внешнего кодогенератора. Я не нашёл. И с чего вдруг переходить на какое-то другое решение, если и своё отлично работает? Если ткнёте, я переходить всё равно не буду, но хотя бы производительность сравню. Мне интересно, во сколько раз у меня быстрее будет.

        И не вижу никакой алогичности. В продакшене бывают ужаснейшие говнокоды, которые здесь конечно же встречаются, и как-то живут.
        Ответить
        • > Ткните носом в готовое решение без внешнего кодогенератора
          В рамках филосовской регрессии: cpp -- это тоже внешний кодогенератор, только кривой и убогий.
          Ответить
          • Смысл в том, что где есть компилятор, там и препроцессор. То есть будет работать всегда и не требует дополнительной настройки.
            Ответить
    • Не соснёт ли эта радость на указателях?
      Ответить
      • Указатели пока не поддерживаются, поэтому не скомпилируется. Понятное дело, unique_ptr добавляется элементарно. Добавить обычные указатели и shared_ptr вроде возможно, но я этим не занимался, потому что решил у себя держать всё как можно ближе к POD - всё в массивах и других контейнерах, хранящихся в памяти линейно. И ссылки делать через индексы в массивах.
        Если у меня это не будет получаться, либо я захочу выложить свои наработки в открытый доступ для других, я наверное займусь реализацией поддержки указателей. А пока займусь другими делами.
        Ответить
        • Итак, ожидаемо всосало. Дело в том, что написать и выложить на всеобщее обозрение некроссплатформенную бинарную сериализацию для простых типов не легко, а очень легко. Это упражнение на конкатенацию на пару часов максимум.
          А вот более-менее нетривиальные случаи приведут к говнокоду, багам и хуёвой производительности.

          > в открытый доступ для других
          Биндинги для других языков уже есть? Хотя бы спецификация формата и поддержка версионирования?
          Ответить
          • Ну всякие big endian и т.п. в планах, вроде говнокода не должно из этого получиться.

            Ни биндингов, ни спецификации. Я же в первую очередь для себя делаю. Ещё даже не выкладывал свою либу.
            Хотя в принципе спецификация проста - все POD'ы сериализуем как есть, остальное по порядку, массивы и строки - длина 4 байта + данные.
            Ответить
      • Ну сделает чё-нибудь типа мапы адрес->оффсет для уже сохранённых объектов... Не так страшен чёрт, как его малевал wvxvw.

        З.Ы. Интересно, а множественное наследование эта либа понимает?
        Ответить
        • > Интересно, а множественное наследование эта либа понимает?

          С виртуальным ещё интересней.
          Ответить
        • У меня только автоматическая сериализация структур без наследования вообще. С наследованием придётся ещё и наследуемые поля дублировать в рефлексии, и тип должен быть известен в runtime. Для всего остального нужно руками перегружать функции для сериализации.
          Можно конечно подумать и попробовать сделать остальное, но мне пока это не нужно, а я делаю только то, что мне нужно в ближайшее время. Если я возьмусь за всё сразу, то я ничего толкового сделать не успею.
          Ответить
          • > наследуемые поля дублировать в рефлексии
            Нафиг? Просто родителей перечислить же. Ну и чтобы родители тоже были сериализуемыми.
            Ответить
            • Ну пока так, потом буду устранять недостатки. Пока я не придумал, как в ADD_REFLECTION запихнуть проверку, есть ли у базовых классов рефлексия.
              Ответить
              • Ну add reflection же чего-то добавляет в класс, раз внутри описан? Вот наличие этого чего-то можно статик ассёртнуть в теории...
                Ответить
                • Надо как-то проверить существование метода или какого-нибудь типа. Через void_t<decltype(...)>, как кто-то писал выше, можно вроде проверить существование чего угодно, но это тоже либо существующий тип, либо не существующий, а не булевое значение. Как из этого достать булевое значение?
                  Другими словами, нужна штука типа такой:
                  type_exists<std::enable_if_t<false>>::va lue == false
                  type_exists<std::enable_if_t<true>>::val ue == true
                  Вот как её сделать?
                  Ответить
                  • через SFINAE:

                    template <typename T, typename dummy = void>
                    struct is_something: std::false_type {};
                    
                    template <typename T>
                    struct is_something<T, void_t</*...*/>>: std::true_type {};
                    Ответить
                    • А у true_type и false_type есть оператор bool.
                      Ответить
                      • И статический член value. Не нужно инстанс создавать (хотя там всё равно constexpr всё приправлено).
                        Ответить
                    • А без определения нового типа это невозможно сделать? А то хотелось бы что-то типа того, что я выше написал.
                      Ответить
                      • Ну ты один раз этот шаблон объявишь, а потом будешь юзать как чё-то типа is_reflected<MyType>::value.
                        Ответить
                        • Это да, но я хочу сделать общий механизм, чтобы и для других целей использовать. А то каждый раз объявлять неудобно.
                          Ответить
                          • Ну х.з., в макрос заверни, раз их так любишь :3
                            DEFINE_TYPE_TRAIT(is_reflected, /* ... */);
                            Ответить
                            • Ну так всё равно придётся его предварительно объявлять. А я хочу иметь возможность делать такие проверки сходу.
                              Ответить
    • rusML.FalseTrueNames[0] = "нет";
      rusML.FalseTrueNames[0] = "да";
      Ответить
      • Ложь - это истина. Истина - это UB.
        Ответить
        • Получается по-другому:

          Ложь - это истина. Истина - ничто.
          Ответить
      • О, ошибочка вышла. Но UB не будет, потому что поле имеет тип StringView, который по умолчанию инициализируется в пустую строчку.
        Ответить
    • Что-то в последнее время слишком много людей публикуют на ГК презентации своих продуктов, работающих в продакшене. Говнокодик медленно, но верно превращается в Говнохабр?
      Ответить
      • У меня не продакшен пока, я это в свободное время пишу и использую сам.
        Ответить
      • Лабы закончились.
        Ответить
    • Использовать нелатинские буквы в исходниках (кроме говнолаб) просто недопустимо. Хотя в говнолабах тоже лучше не использовать, чтобы потом эта говнопривычка не перешла на что-то другое.
      Ответить
      • обоснуй
        Ответить
        • Если в исходниках кириллическое или какое-либо еще говно, не входящее в ASCII, то сами файлы окажутся кодировко-зависимыми, т.е. зависят от того, в какой именно говнокодировке нахуячен неASCII текст в .c файлах. И если кто-то писал строки в KOI8-R или CP1251 то это говно надо еще перекодировать в другое говно. Но это говно НЕ ВСЕГДА можно автоматически перекодировать
          Допустим, какой-то мудень написал
          char govno[6] = "Говно";

          И если эта поебень закодирована в 8-битной говнокодировке, типа windows-1251 или KOI8-R то если просто в лоб перекодировать эту поеботу в UTF-8 то будет некомпилируемая хуита. Если в этой строке закодированной в однобайтной говнокодировке меняет одну букву на другую
          govno[0] = 'г';

          то эта поебень при конвертации в UTF-8 тоже сломается нахуй. Продолжать?
          Ответить
          • Ах да, далеко не все ОС и редакторы поддерживают все возможные говнокодировки. Под шиндошс даже говнокостыли сделали, чтобы там запускать японские порноигры всякие
            Ответить
            • > шиндошс даже говнокостыли сделали

              Это про applocale? Оно же deprecated ещё с XP.
              Ответить
          • Ты привел примеры какого-то говнокода, но из этих примеров не следует, что "Использовать нелатинские буквы в исходниках (кроме говнолаб) просто недопустимо". Из этих примеров следует, что писать говнокод - плохо.
            А если я хочу писать комментарии на русском? А если я хочу использовать эмодзи в качестве идентификаторов? А если у меня файлы в утф-8 и мой код ищет на странице, скачанной из интернета подстроку "ソサイクダサイ" с помощью std::string::find, например? Почему это мне нельзя это делать?
            Ответить
            • Учитывая, что std::string вообще не предназначен для работы с кодировками переменной длины... В принципе. Когда-то я ковырялся с потоками, чтобы заставить определение длины выводимого текста работать нормально и обнаружил, что попытка заставить char_traits работать для не fixed-width кодировок приводит к UB.

              > А если я хочу использовать эмодзи в качестве идентификаторов?

              То ты мудак. У меня дикая ненависть к японцам из-за их любви использовать свой мунспик в идентификаторах. Из-за чего нормально локализовать некоторые вещи не получается и вообще ковыряться в коде — боль.
              Ответить
      • Я держу все файлы только в UTF-8 и все функции моей библиотеки работают только с UTF-8. Поэтому никакой непереносимости нет - работает со всеми компиляторами и всеми ОС.
        Ответить
        • Тебе найти ОС, которая не умеет в UTF-8?
          Ответить
          • BolgenOS - долой скучные обои
            Ответить
          • А давайте закопаем уже ОС, которые в 2016 не умеют в UTF-8.
            Ответить
          • А при чём тут ОС? Это просто представление данных. Главное, что моя программа умеет и компиляторы умеют.
            Под "все ОС" я имел в виду Linux\FreeBSD и подобные, которые даже на уровне стандартных библиотек C\C++ работают с UTF-8 по умолчанию, а также винду, на которой я тоже добился того, чтобы UTF-8 строки выводились на консоль, MessageBox, и вообще обрабатывались моей либой корректно. А стандартные либы я просто не использую.
            Разве что иногда приходится следить, чтобы винда\студия не сохраняла исходники в CP1251. Но для этого у меня есть программа для преобразования кодировок файлов с нужным расширением в папке рекурсивно. Я запускаю её раз в несколько месяцев и иногда вижу там несколько файлов в CP1251, которые преобразуются в UTF-8.
            Ответить
            • > и иногда вижу там несколько файлов в CP1251
              Т.е. всё это время вместо строк из этих файлов юзерам показывается какая-то левая хуйня?
              Ответить
              • Ну чаще всего в таких файлах только комментарии, которые ни на что не влияют. Изредка бывает, что ошибки кракозябрами вылезают. А больше я ничего на русском и не держу. Но вообще я пока единственный юзер своих проектов, хотя хочу это в ближайшее время изменить.
                Ответить
            • > на уровне стандартных библиотек C\C++ работают с UTF-8

              Это где ты в стандартной библиотеке C нашел функции для работы с юникодом? В плюсах-то они вполне могут быть в новых стандартах, хуй знает что там эти норкоманы нахуевертили
              Ответить
              • Тот же printf в консоль нормально юникод печатает, в отличие от винды.
                Ответить
                • Не, это консоль понимает, что поток байтов это текст в утф8 и отоброжает нормально. Попробуй стандартными средствами получить длину текста в символах, изменит n-й символ и подобное. (Тут кресты соснули — даже в сишной либе есть средства для этого). Самое весёлое это форматированый вывод. Вывести текст в утф8 с паддингом под 10 символов без велосипедов не выйдет.
                  Ответить
                • Смотрите, типичный прыщедебил - в прыщах utf8 работает, в винде нет - значит, винда говно. А то что в ней юникод в консоль можно наверно минимум с nt4 выводить (фар тому пример), оно не знает.
                  Ответить
                  • 3_14dar
                    Смотрите, типичный прыщедебил

                    Мухаха
                    Ответить
                  • Не, но тут какой-то терминальный случай. В линуксе всё работает. Блядь, даже в мёртвой фрибсд уже работает. А в винде всё ещё нужны заклинания и ебля.
                    Ответить
                    • Что работает и для чего нужны заклинания?
                      Ответить
                    • А чего это FreeBSD мёртвая? Вроде говорят, она самая стабильная и безбажная, и поэтому на ней сервера делают. Да ещё и лицензия BSD, а не GPL. И новые версии регулярно продолжают выходить.
                      А в винде видимо не хотели ломать обратную совместимость. Хотя могли бы хотя бы wcout научить без танцев с бубном выводить Юникодовые символы.
                      Ответить
                    • > всё работает
                      Если отойти от консолечки и оценить срачики, оказывается, что
                      1. С точки зрения пользователя А в системе А всё работает, а в системе Б ничего не работает, надо долго настраивать.
                      2. С точки зрения пользователя Б в системе Б всё работает, а в системе А ничего не работает, надо долго настраивать.
                      3. С точки зрения В в системах А и Б вообще абсолютно всё работает, а А и Б - ламеры и не умеют настраивать.
                      Разумеется, под словом "всё" понимается "всё, что нужно пользователю А/Б", а А и Б счастливы и выбрали ОС, идеально подходящую под их задачи, а В - неленивый.
                      Интересно, будет ли ОС, где А и Б смогут реально всё использовать без боли. Подойдёт ли на эту роль Windows 10 с экстрактом линукса?
                      Ответить
              • Не, нету ничего. Есть только для конверсии из/в UTF8.

                Там пока рассматривается отдельные функции для ASCII текста, чтобы локали ПИРФОМАНС не убивали. УТФ8 дай бог в этом столетии появится.
                Ответить
      • Мне вот в питоне концепция понравилась: не объявил явно, в какой кодировке файл - всё кроме ascii идёт нахуй.
        Ответить
        • Но зато в работе с кодировками в самом питоне ебля ещё та. Особенно в питоне2.

          То ли дело php
          Ответить
          • Там ёбля разве что из-за неявного каста... Пиндосы забывают encode/decode, а потом это говно крашится на первом же не аски символе...
            Ответить
            • >> Там ёбля разве что из-за неявного каста...

              "- Я посмотрел твой код и нашел там неявный каст. Сымай штанишки"
              Ответить
              • А, вот для чего некоторые программисты оставляют неявные касты!
                Ответить

    Добавить комментарий