Как сделать литерал

Обновлено: 07.07.2024

C++11 представляет пользовательские литералы что позволит ввести новый синтаксис литералов на основе существующих литералов ( int , hex , string , float ), чтобы любой тип мог иметь буквальное представление.

примеры:

на первый взгляд это выглядит очень круто, но мне интересно, насколько это применимо, когда я пытался думать о суффиксах _AD и _BC создать даты, я обнаружил, что это проблематично из-за того оператора. 1974/01/06_AD сначала оценить 1974/01 (как обычный int s) и только позже 06_AD (не говоря уже об августе и сентябре, которые должны быть написаны без 0 для восьмеричной причинам). Это можно обойти, имея синтаксис be 1974-1/6_AD так что порядок оценки оператора работает, но он неуклюжий.

Итак, мой вопрос сводится к тому, считаете ли вы, что эта функция оправдает себя? Какие другие литералы вы хотели бы определить, которые сделают ваш код c++ более читаемым?

обновленный синтаксис в соответствии с окончательным проектом июня 2011

вот случай, когда есть преимущество использования пользовательских литералов вместо вызова конструктора:

преимущество заключается в том, что исключение времени выполнения преобразуется в ошибку времени компиляции. Вы не можете добавить статическое утверждение к ctor битового набора, принимая строку (по крайней мере, не без аргументов шаблона строки).

на первый взгляд, это кажется простым синтаксическим сахаром.

но, глядя глубже, мы видим, что это больше, чем синтаксический сахар, как он расширяет параметры пользователя C++ для создания пользовательских типов, которые ведут себя точно так же, как отдельные встроенные типы. в этом, этот маленький "бонус" является очень интересным дополнением C++11 К c++.

нам действительно нужно это на C++?

Я вижу несколько применений в коде, который я написал в последние годы, но только потому, что я не использовать его в C++ не значит что это не интересно другой разработчик C++.

мы использовали в C++ (и в C, я думаю), определяемые компилятором литералы, для ввода целых чисел как коротких или длинных целых чисел, вещественных чисел как float или double (или даже long double), а символьные строки как обычные или широкие символы.

в C++ у нас была возможность создавать собственные типы (т. е. классы), потенциально без накладных расходов(inlining и т. д.). У нас был возможность добавлять операторы к своим типам, чтобы они вели себя как аналогичные встроенные типы, что позволяет разработчикам C++ использовать матрицы и комплексные числа так же естественно, как если бы они были добавлены к самому языку. Мы даже можем добавить операторы приведения (что обычно является плохой идеей, но иногда это просто правильное решение).

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

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

вам действительно нужно это на C++?

этот вопрос для вы ответ. Не Бьярне Страуструп. Не Херб Саттер. Не любой член стандартного комитета C++. Вот почему у вас есть выбор в C++, и они не будут ограничивать полезную нотацию только встроенными типами.

если вы нужно это, то это желанное дополнение. Если вы не, что ж. Не используй его. Это вам ничего не будет стоить.

обожралась. Покажи мне свои комплексы.

существует разница между раздутым и сложным (каламбур предназначен).

как показано Нильсом в какие новые возможности добавляют пользовательские литералы в C++?, возможность написать комплексное число является одной из двух функций, добавленных "недавно" в C и C++:

теперь, и C99" двойной сложный " тип и C++ "std::complex" тип могут быть умножены,добавлены, вычитаются и т.д. используя перегрузку операторов.

но в C99 они просто добавили другой тип в качестве встроенного типа и встроенную поддержку перегрузки оператора. И они добавили еще одну встроенную буквальную функцию.

в C++ они просто использовали существующие функции языка, видели, что буквальная функция была естественной эволюцией языка, и так добавил он.

в C, если вам нужно такое же улучшение обозначения для другого типа, вам не повезло, пока ваше лоббирование не добавит ваши квантовые волновые функции (или 3D-точки или любой базовый тип, который вы используете в своей области работы) к стандарту C в качестве встроенного типа.

в C++11, вы просто можете сделать это сами:

он раздут? Нет!--9-->, необходимость есть, как показано, как и C и C++ комплексы нуждаются в способе представления их буквальные сложные значения.

он неправильно спроектирован? Нет!--9-->, он разработан как и любая другая функция C++, с учетом расширяемости.

это только для обозначения целей? Нет!--9-->, поскольку он может даже добавить безопасность типов в ваш код.

например, давайте представим CSS-ориентированный код:

тогда очень легко обеспечить строгое типирование для присвоения значений.

Is опасно?

хороший вопрос. Могут ли эти функции быть пространствами имен? Если да, то джекпот!

в любом случае,как и все, вы можете убить себя, если инструмент используется неправильно. C является мощным,и вы можете стрелять в голову, если вы злоупотребляете пистолетом C. У C++ есть пистолет C, а также скальпель, электрошокер и любой другой инструмент, который вы найдете в инструментарии. Ты можешь злоупотребить скальпелем и истечь кровью. Или вы можете построить очень элегантный и надежный код.

Итак, как и каждая функция c++, вам действительно это нужно? Это вопрос вы должны ответить, прежде чем использовать его в C++. Если вы этого не сделаете, это ничего вам не будет стоить. Но если вам это действительно нужно, по крайней мере, язык вас не подведет.

ваша ошибка, как мне кажется, заключается в том, что вы смешиваете операторов:

этого нельзя избежать, потому что / быть оператор, компилятор должен интерпретировать его. И, AFAIK, это хорошо вещь.

чтобы найти решение вашей проблемы, я бы написал литерал каким-то другим способом. Например:

лично я бы выбрал число и даты ISO, но это зависит от ваших потребностей. В этом весь смысл, позволяя пользователю определять свои собственные литеральные имена.

Это очень хорошо для математического кода. Из моего ума я вижу использование следующих операторов:

градусов на градусов. Это делает написание абсолютных углов гораздо более интуитивным.

Он также может использоваться для различных представлений с фиксированной точкой (которые все еще используются в области DSP и графики).

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

универсальные связи данных находятся в пространстве имен (и могут быть импортированы с помощью деклараций, директив, но вы не можете явно задать пространство имен в буквальном как 3.14std::i ), Что означает, что (надеюсь) не будет тонны столкновений.

тот факт, что они на самом деле могут быть шаблонных (и таких бы) означает, что вы можете сделать некоторые довольно мощная штука с универсальные связи данных. Авторы Bigint будут очень рады, так как они могут, наконец, иметь сколь угодно большие константы, рассчитанные во время компиляции (через constexpr или шаблоны.)

мне просто грустно, что мы не увидим пару полезных литералов в стандарте (С виду), например s на std::string и i для мнимой единицы.

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

позвольте мне добавить немного контекста. Для нашей работы очень нужны пользовательские литералы. Мы работаем на MDE (Model-Driven Engineering). Мы хотим определить модели и метамодели в C++. Мы фактически реализовали отображение из Ecore в C++ (EMF4CPP).

проблема возникает, когда можно определить элементы модели как классы в C++. Мы используем подход преобразования метамодели (Ecore) в шаблоны с аргументами. Аргументами шаблона являются структурные характеристики типов и классов. Например, класс с двумя атрибутами int будет выглядеть примерно так:

однако, получается, что каждый элемент в модели или метамодели, как правило, имеет название. Мы хотели бы написать:

но, C++, ни C++0x не позволяют этого, так как строки запрещены в качестве аргументов для шаблонов. Вы можете написать имя char за char, но это, по общему признанию, беспорядок. С правильными определяемыми пользователем литералами мы могли бы написать нечто подобное. Скажем, мы используем " _n " для идентификации имен элементов модели (я не использую точный синтаксис, просто чтобы сделать идею):

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

Бьярне Страуструп говорит об UDL в этом C++11 talk, в первом разделе о интерфейсах с богатым типом, около 20 минут.

его основной аргумент для универсальные связи данных принимает форму силлогизма:

"тривиальные" типы, т. е. встроенные примитивные типы, могут улавливать только тривиальные ошибки типа. Интерфейсы с более богатыми типами позволяют системе типов улавливать больше видов ошибок.

виды ошибок типа, которые богато набранный код может повлиять на реальный код. (Он приводит пример климатического орбитального аппарата Марса, который печально провалился из-за ошибки измерений в важной константе).

в реальном коде единицы редко используются. Люди не используют их, потому что выполнение вычислений во время выполнения или накладных расходов памяти для создания богатых типов слишком дорого, а использование ранее существовавшего шаблонного кода единицы C++ настолько уродливо, что его никто не использует. (Эмпирически, никто не использует его, даже если библиотеки существуют уже десять лет).

поэтому, чтобы заставить инженеров использовать единицы в реальном коде, нам нужно устройство, которое (1) не несет никаких накладных расходов во время выполнения и (2) является условно приемлемым.

поддержка проверки измерений во время компиляции-единственное необходимое обоснование.

см., например,PhysUnits-CT-Cpp11, небольшая библиотека заголовков C++11, C++14 только для компиляционного анализа размеров и обработки и преобразования единиц/количеств. Проще, чем импульс.Единицы поддерживает символ блок литералы, такие как m, g, s, метрические префиксы например, m, k, M, зависит только от стандартной библиотеки C++ , SI-только, интегральные степени измерений.

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

. Интересно, как бы ты выразился сегодня. У вас будет класс KG и LB, и вы сравните скрытые объекты:

и это тоже подойдет. С типами, которые имеют более длинные имена или типы, которые вы не надеетесь иметь такой хороший конструктор для sans написания адаптера, это может быть хорошим дополнением для создания и инициализации неявного объекта на лету. С другой стороны, вы уже можете создавать и инициализировать объекты с помощью методов,.

но я согласен с Нильсом по математике. Например, функции тригонометрии C и c++ требуют ввода в радианы. Я думаю, в градусах, поэтому очень короткое неявное преобразование, такое как Nils, очень приятно.

в конечном счете, это будет синтаксический сахар, однако, но это будет иметь небольшое влияние на читаемость. И, вероятно, будет легче написать некоторые выражения (sin(180.0 deg) легче написать, чем sin(deg (180.0)). И тогда будут люди, которые злоупотребляют этой концепцией. Но тогда люди, злоупотребляющие языком, должны использовать очень ограничительные языки, а не что-то вроде выразительные как C++.

Ах, мой пост говорит в основном ничего, кроме: все будет хорошо, влияние не будет слишком большим. Давай не будем волноваться. :-)

Я никогда не нуждался или не хотел эту функцию (но это может быть Буль эффект). Моя реакция на коленный рывок заключается в том, что он хромает и, вероятно, понравится тем же людям, которые думают, что здорово перегрузить operator+ для любой операции, которая может быть удаленно истолкована как добавление.

C++ обычно очень строг в отношении используемого синтаксиса-за исключением препроцессора, вы можете использовать не так много для определения пользовательского синтаксиса / грамматики. Е. Г. мы можем перегрузить существующие operatos, но мы не можем определить новые - ИМО это очень созвучно духу с++.

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

даже предполагаемое использование может значительно затруднить чтение источника код: одна буква может иметь обширные побочные эффекты, которые никоим образом не могут быть идентифицированы из контекста. С симметрией до u, l и f большинство разработчиков будут выбирать одиночные буквы.

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

Я вижу определенный смысл в комбинация с "авто", также в сочетании с библиотекой единиц, как boost units, но недостаточно, чтобы заслужить это обожание.

интересно, однако, какие умные идеи мы придумываем.

я использовал пользовательские литералы для двоичных строк, таких как:

используя std::string(str, n) конструктор так что не разрезать нитку пополам. (Проект выполняет большую работу с различными форматами файлов.)

Это было полезно также, когда я угробил std::string в пользу обертки для std::vector .

линейный шум в этой штуке огромен. И читать ужасно.

Дайте мне знать, они объяснили, что новое добавление синтаксиса с любыми примерами? Например, есть ли у них пара программ, которые уже используют C++0x?

для меня эта часть:

не оправдывает эту часть:

даже если вы используете I-синтаксис в 1000 других строках. Если вы пишете, вы, вероятно, пишете 10000 строк чего-то и еще кое-что. Особенно, когда вы все равно, вероятно, напишете в основном везде это:

"авто" - ключевое слово может быть оправдано, хотя, только возможно. Но давайте возьмем только C++, потому что это лучше, чем C++0x в этом аспекте.

это похоже.. так просто. Даже думал, что все std и заостренные скобки просто хромают, если вы используете его повсюду. Я не начинаю догадываться, какой синтаксис есть в C++0x для поворота std::complex под сложный.

это, возможно, что-то простое, но я не верю, что это так просто в C++0x.

в любом случае, дело в том, что: написание 3.14 i вместо std::complex(0, 3.14); не экономит вам много времени в целом, за исключением нескольких супер особых случаев.

U Ser D efined L iterals (UDL) добавляют в C ++ от C ++ 11. Хотя C ++ предоставляет литералы для различных встроенных типов, но они ограничены.

Примеры литералов для встроенных типов:

Почему мы используем UDL?
Давайте рассмотрим приведенный ниже пример, чтобы понять необходимость UDL.

Для вычисления вышеуказанного соотношения необходимо преобразовать их в одинаковые единицы. UDL помогают нам преодолеть стоимость перевода единиц. Мы можем определить пользовательские литералы для пользовательских типов и новую форму литералов для встроенных типов. Они помогают сделать константы в коде более читабельными. Значение UDL заменяется фактическим значением, определенным в коде компилятором во время компиляции. UDL не экономят большую часть времени кодирования, но все больше и больше вычислений можно перенести во время компиляции для более быстрого выполнения.

Примеры пользовательских литералов:

Пример 1:

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

Любая статья является изложением знаний в общем случае. У многих людей мышление устроено так, что прочтя на форуме конкретный вопрос и конкретный ответ на этот вопрос, у них появится бОльшее понимание, чем после прочтения теоретических выкладок (даже если они подкреплены конкретными примерами). Ссылки на такие обсуждения я, как правило, включаю в последний раздел статьи.

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

  • 1. Общие сведения
  • 2. Строковой литерал на позиции инициализатора массива char'ов
  • 3. Строковой литерал внутри оператора sizeof
  • 4. Строковой литерал во всех прочих случаях
  • 5. Какие из всего этого следуют выводы
    5.1. Хранение больших массивов строк
    5.2. Когда можно, а когда нельзя модифицировать строку
    5.3. Возврат строки из функции
    5.4. Переиспользование памяти под неявные объекты для строк
    5.5. Применение оператора [] к строковому литералу
  • 6. Склеивание строковых литералов компилятором
  • 7. Ссылки на темы, где обсуждался данный вопрос


1. Общие сведения

Ещё одна конструкция языков Си и Си++, которая часто приводит в затруднение начинающих - это строковой литерал. Начинающим, как правило, трудно понять, чем принципиально отличаются две следующие конструкции:

Термин "строка" имеет очень много смыслов, с технической стороны различающихся в разных контекстах. В контексте языков типа Бэйсик или Паскаль слово "строка" имеет один смысл, в контексте C'шного заголовочного файла string.h - другой смысл, в контексте C++'ного заголовочного файла string - третий смысл, и т.д. Чтобы не путаться с прочими смыслами, я буду пользоваться техническим термином "строковой литерал", который по смыслу означает "строковая константа". Строковым литералом называется заключённая в двойные кавычки строка.

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


2. Строковой литерал на позиции инициализатора массива char'ов

Первая возможность использования строкового литерала - это инициализация массива char'ов. Данная конструкция возникает только в тех случаях, когда описывается переменная, являющаяся массивом char'ов и через знак " margin: 5px 10px 5px 30px">

ВНИМАНИЕ!
В первом комментарии к статье мне любезно сообщили об ошибке. Поведение для Си и для Си++ немного различается. А потому нижеидущий текст (до конца раздела 2) гарантированно справедлив для языка Си, но требует небольшой доработки для языка Си++

При этом есть один очень хитрый момент, касающийся включения в этот инициализатор элемента '\0'. И этот момент иногда вводит в заблуждение даже тех, кто имеет хороший опыт программирования. Если массив задан без указания размера (т.е. с пустыми квадратными скобками), то в инициализатор включается хвостовой символ '\0', как это было указано в вышеидущем примере. Т.е., условно говоря, sizeof от инициализатора (и, соответственно, переменной типа массив) будет равен количеству символов в строке плюс единица. Однако если у массива указан размер, то хвостовой '\0' в инициализатор НЕ включается.

Таким образом, если мы напишем

то такая запись будет эквивалентной

По общим правилам языков C/C++ для инициализации массива в случаях, когда инициализатор имеет меньшее число элементов, чем инициализируемая переменная, хвост инициализатора дописывается нулями соответствующего типа. И в данном случае такую запись можно трактовать как

Хитрость заключается в том, что если мы укажем размер массива равный 3, то хвостового нуля в инициализаторе уже не будет (потому что размер инициализатора совпадает с размером массива). При этом код остаётся абсолютно корректным с точки зрения языка, хотя начинает представлять собой некоторый бардак с точки зрения программиста, который слишком привык к тому, что под строкой подразумевается набор символов с хвостовым нулём.

Если мы напишем такой пример:

то при исполнении на многих компиляторах мы получим код, который при исполнении напечатает нам "abcdefghi". Связано это с тем, что компилятор, как правило, положит три массива "a", "b" и "c" в память подряд друг за другом и таким образом в памяти сформируется набор данных размером 10 байт: 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', '\0'. Когда мы подаём в printf указатель на массив "a", то внутри себя функция printf уже не знает ни о каких переменных и будет работать с этим указателем как со строкой: т.е. с набором символов, который заканчивается нулём.

является ошибочной, потому как размер инициализатора больше, чем размер массива.

В случае с инициализацией многомерных массивов char'ов имеем всё ровно то же самое:

Что такое текст, думаю, знают все. А что такое строка в JavaScript? Строка в JavaScript – это последовательность 16-битных значений, каждое значение является, в большинстве случаев, символом Юникода. Длина строки – количество 16-битных значений. Пустая строка – строка, длина которой равна 0.

Строковые литералы – символы, заключенные в одинарные или двойные кавычки. Для понимания: примеры строковых литералов.

В строковых литералах (в языке JavaScript) есть небольшая проблема, доставляющая неудобство. Строковые литералы должны быть записаны на одной строке и если вы разобьете фразу на две строки, то возникнет ошибка. Но разработчики JavaScript’a решили проблему так: после каждой строки ставить обратный слэш (\). Но здесь нужно быть очень внимательным! Если после обратного слэша есть хоть какой-то символ, даже пробел, то это получается опять ошибка. Далее пример:

Как подсчитать длину строки?

Свойство length можно использовать, чтобы определить длину строки. Далее пример:

Читайте также: