Нет любви C ++, когда речь идет о «скрытых особенностях» ряда вопросов? Подумал, что выкину его там. Какие скрытые возможности C ++?
c++
hidden-features
Craig H
источник
источник
Ответы:
Большинство программистов на C ++ знакомы с тернарным оператором:
Однако они не понимают, что его можно использовать как lvalue:
что является сокращением для
Используйте с осторожностью :-)
источник
(value ? function1 : function2)()
.function1
иfunction2
неявно преобразуются в указатели функций, а результат неявно преобразуется обратно.Вы можете без ошибок помещать URI в исходный код C ++. Например:
источник
goto
, которая есть в C ++). Все, что следует за двумя косыми чертами, является комментарием. Следовательно, сhttp://stackoverflow.com
,http
- это метка (теоретически вы могли бы написатьgoto http;
) и//stackoverflow.com
просто комментарий в конце строки. Оба они допустимы для C ++, поэтому конструкция компилируется. Конечно, он не делает ничего неопределенно полезного.goto http;
, на самом деле не следует по URL. :(Программисты на C ++ предпочитают избегать указателей из-за возможных ошибок.
Но самый крутой C ++, который я когда-либо видел? Аналоговые литералы.
источник
Я согласен с большинством постов там: C ++ - это язык с множеством парадигм, поэтому «скрытые» функции, которые вы найдете (кроме «неопределенного поведения», которого вам следует избегать любой ценой), - это умное использование возможностей.
Большинство этих возможностей не являются встроенными функциями языка, а основаны на библиотеках.
Самым важным является RAII , который часто игнорируется разработчиками C ++ из мира C. Перегрузка оператора часто является неправильно понимаемой функцией, которая обеспечивает как поведение, подобное массиву (оператор индекса), операции, подобные указателям (интеллектуальные указатели), так и операции, подобные встроенным (умножение матриц.
Использование исключения часто затруднено, но при некоторой работе можно получить действительно надежный код благодаря безопасности исключений. спецификаций (включая код, который не будет терпеть неудачу, или который будет иметь функции, подобные фиксации, которые будут успешными или вернутся к исходное состояние).
Самая известная из «скрытых» функций C ++ - метапрограммирование шаблонов. , поскольку оно позволяет вам частично (или полностью) выполнять вашу программу во время компиляции, а не во время выполнения. Однако это сложно, и вы должны хорошо разбираться в шаблонах, прежде чем пробовать это делать.
Другие используют множественную парадигму для создания «способов программирования» вне предка C ++, то есть C.
Используя функторы , вы можете моделировать функции с дополнительной безопасностью типов и сохранением состояния. Используя шаблон команды , вы можете отложить выполнение кода. Большинство других шаблонов проектирования могут быть легко и эффективно реализованы на C ++ для создания альтернативных стилей кодирования, которые не должны находиться в списке «официальных парадигм C ++».
Используя шаблоны , вы можете создать код, который будет работать с большинством типов, включая не тот, который вы думали вначале. Вы также можете повысить безопасность типов (например, автоматический тип malloc / realloc / free). Возможности объектов C ++ действительно эффективны (и, следовательно, опасны при неосторожном использовании), но даже у динамического полиморфизма есть статическая версия в C ++: CRTP .
Я обнаружил, что большинство книг типа " Эффективный C ++ " от Скотта Мейерса или книг типа " Исключительный C ++ " от Херба Саттера одновременно удобны для чтения и представляют собой кладезь информации об известных и менее известных особенностях C ++.
Среди моих предпочтений есть тот, который должен заставить любого Java-программиста встать дыбом от ужаса: в C ++ наиболее объектно-ориентированный способ добавить функцию к объекту - использовать функцию, не являющуюся членом, а не дружественную функцию, а не член- функция (т.е. метод класса), потому что:
В C ++ интерфейс класса - это как его функции-члены, так и функции, не являющиеся членами, в одном пространстве имен.
не являющиеся друзьями функции, не являющиеся членами, не имеют привилегированного доступа к внутреннему классу. Таким образом, использование функции-члена вместо не-члена, не являющегося другом, ослабит инкапсуляцию класса.
Это не перестает удивлять даже опытных разработчиков.
(Источник: среди прочего, Интернет-гуру недели Херба Саттера №84: http://www.gotw.ca/gotw/084.htm )
источник
Одна языковая функция, которую я считаю несколько скрытой, потому что я никогда не слышал о ней за все время учебы в школе, - это псевдоним пространства имен. Это не было доведено до моего сведения, пока я не наткнулся на примеры в документации по усилению. Конечно, теперь, когда я знаю об этом, вы можете найти его в любом стандартном справочнике по C ++.
источник
using
.В инициализации
for
цикла можно объявлять не только переменные , но также классы и функции.Это позволяет использовать несколько переменных разных типов.
источник
Оператор массива ассоциативен.
A [8] является синонимом * (A + 8). Так как сложение ассоциативно, его можно переписать как * (8 + A), что является синонимом ..... 8 [A]
Вы не сказали, что полезно ... :-)
источник
A
не имеет значения. Например, если быA
были achar*
, код все равно был бы действителен.Мало что известно о том, что союзы тоже могут быть шаблонами:
И у них тоже могут быть конструкторы и функции-члены. Ничего общего с наследованием (включая виртуальные функции).
источник
From
иTo
установлены и используются соответствующим образом. Однако такое объединение можно использовать с определенным поведением (сTo
массивом беззнаковых символов или структурой, совместно использующей исходную последовательностьFrom
). Даже если вы используете его неопределенным образом, он все равно может быть полезен для низкоуровневой работы. В любом случае, это всего лишь один пример шаблона объединения - могут быть другие варианты использования шаблонного объединения.C ++ - это многопарадигмальный язык, вы можете поставить последние деньги на то, что в нем есть скрытые функции. Один из примеров: метапрограммирование шаблона . Никто в комитете по стандартам не намеревался создать полный по Тьюрингу подъязык, который запускается во время компиляции.
источник
Еще одна скрытая функция, которая не работает в C, - это функциональность унарного
+
оператора. Вы можете использовать его для продвижения и разложения самых разных вещейПреобразование перечисления в целое число
И значение вашего перечислителя, которое раньше имело тип перечисления, теперь имеет идеальный целочисленный тип, который может соответствовать его значению. Вручную вы вряд ли узнаете этот тип! Это необходимо, например, когда вы хотите реализовать перегруженный оператор для перечисления.
Получить значение из переменной
Вы должны использовать класс, который использует статический инициализатор внутри класса без определения вне класса, но иногда он не может связать? Оператор может помочь создать временный объект, не делая предположений или зависимостей от его типа.
Распад массива на указатель
Вы хотите передать функции два указателя, но это просто не сработает? Оператор может помочь
источник
Время жизни временных файлов, привязанных к константным ссылкам, мало кому известно. Или, по крайней мере, это моя любимая часть знаний о C ++, о которой большинство людей не знает.
источник
Приятной особенностью, которая используется нечасто, является блок try-catch для всей функции:
Основное использование будет заключаться в преобразовании исключения в другой класс исключения и повторном вызове или в преобразовании между исключениями и обработкой кода ошибки на основе возврата.
источник
return
поймать блок Function Try, только перебросить.Многие знают о метафункции
identity
/id
, но для случаев, не связанных с шаблоном, есть хороший вариант использования: Упростите написание объявлений:Это очень помогает при расшифровке объявлений C ++!
источник
template<typename Ret,typename... Args> using function = Ret (Args...); template<typename T> using pointer = *T;
->pointer<function<void,int>> f(pointer<function<void,void>>);
илиpointer<void(int)> f(pointer<void()>);
илиfunction<pointer<function<void,int>>,pointer<function<void,void>>> f;
Довольно скрытая особенность заключается в том, что вы можете определять переменные в условии if, и его область действия будет охватывать только if и его блоки else:
Некоторые макросы используют это, например, чтобы обеспечить некоторую "заблокированную" область видимости, например:
Также BOOST_FOREACH использует его под капотом. Чтобы завершить это, это возможно не только в if, но и в переключателе:
и в цикле while:
(а также в состоянии for). Но я не уверен, насколько они полезны :)
источник
if((a = f()) == b) ...
, но этот ответ фактически объявляет переменную в условии.for(...; int i = foo(); ) ...;
This будет проходить через тело, покаi
истинно, инициализируя его каждый раз снова. Цикл, который вы показываете, просто демонстрирует объявление переменной, но не объявление переменной, которое одновременно действует как условие :)Предотвращение вызова оператора запятой перегрузок оператора
Иногда вы правильно используете оператор запятой, но вы хотите, чтобы ни один пользовательский оператор запятой не мешал, потому что, например, вы полагаетесь на точки последовательности между левой и правой стороной или хотите убедиться, что ничто не мешает желаемому действие. Вот где
void()
вступает в игру:Игнорируйте заполнители, которые я поставил для условия и кода. Важно то
void()
, что заставляет компилятор использовать встроенный оператор запятой. Иногда это может быть полезно при реализации классов свойств.источник
Инициализация массива в конструкторе. Например, в классе, если у нас есть массив
int
as:Мы можем инициализировать все элементы в массиве по умолчанию (здесь все элементы массива равны нулю) в конструкторе как:
источник
Ооо, вместо этого я могу составить список ненависти к животным:
С положительной стороны
источник
Вы можете получить доступ к защищенным данным и функциям любого класса без неопределенного поведения и с ожидаемой семантикой. Прочтите, чтобы узнать, как это сделать. Также прочтите об этом отчет о дефекте .
Обычно C ++ запрещает вам доступ к нестатическим защищенным членам объекта класса, даже если этот класс является вашим базовым классом.
Это запрещено: вы и компилятор не знаете, на что на самом деле указывает ссылка. Это может быть
C
объект, и в этом случае класс неB
имеет никакого отношения к своим данным. Такой доступ предоставляется только в том случае, еслиx
это ссылка на производный класс или производный от него класс. И он может позволить произвольному фрагменту кода читать любой защищенный член, просто создавая «одноразовый» класс, который считывает элементы, напримерstd::stack
:Конечно, как видите, это нанесет слишком большой ущерб. Но теперь указатели на элементы позволяют обойти эту защиту! Ключевым моментом является то, что тип указателя на член привязан к классу, который фактически содержит указанный член, а не к классу, который вы указали при получении адреса. Это позволяет нам обойти проверку
И, конечно, это тоже работает с
std::stack
примером.Это будет еще проще с объявлением using в производном классе, которое делает имя члена общедоступным и ссылается на член базового класса.
источник
Еще одна скрытая особенность заключается в том, что вы можете вызывать объекты класса, которые можно преобразовать в указатели на функции или ссылки. Разрешение перегрузки выполняется по их результатам, и аргументы передаются безупречно.
Они называются «суррогатными функциями вызова».
источник
Скрытые возможности:
Если функция генерирует исключение, не указанное в ее спецификациях исключения, но функция имеет
std::bad_exception
в своей спецификации исключения, исключение преобразуетсяstd::bad_exception
и генерируется автоматически. Таким образом вы хотя бы узнаете, чтоbad_exception
был брошен. Подробнее читайте здесь .функциональные блоки try
Ключевое слово template для устранения неоднозначности typedef в шаблоне класса. Если имя шаблон члена специализации появляется после
.
,->
или::
оператора, и это имя имеет явно квалифицированные параметры шаблона, префикс имя шаблона члена с ключевыми словами шаблона. Подробнее читайте здесь .Значения по умолчанию для параметров функции могут быть изменены во время выполнения. Подробнее читайте здесь .
A[i]
работает так же хорошо, какi[A]
Временные экземпляры класса можно изменять! Неконстантная функция-член может быть вызвана для временного объекта. Например:
Подробнее читайте здесь .
Если два разных типа присутствуют до и после выражения оператора
:
ternary (?:
), то результирующий тип выражения является наиболее общим из двух. Например:источник
map::operator[]
создает запись, если ключ отсутствует, и возвращает ссылку на созданное по умолчанию значение записи. Итак, вы можете написать:Я поражен тем, сколько программистов на C ++ этого не знают.
источник
.find()
.const map::operator[]
генерирует сообщения об ошибках»Помещение функций или переменных в безымянное пространство имен не рекомендуется использовать
static
для ограничения их областью файлов.источник
static
в глобальном масштабе это никоим образом не является устаревшим. (Для справки: C ++ 03 §D.2)static
использование должно использоваться только внутри класса или функции.Особого внимания требует определение обычных функций друзей в шаблонах классов:
В этом примере два разных экземпляра создают два идентичных определения - прямое нарушение ODR
Поэтому мы должны убедиться, что параметры шаблона шаблона класса присутствуют в типе любой дружественной функции, определенной в этом шаблоне (если мы не хотим предотвратить создание более одного экземпляра шаблона класса в конкретном файле, но это маловероятно). Давайте применим это к варианту нашего предыдущего примера:
Отказ от ответственности: я вставил этот раздел из C ++ Templates: The Complete Guide / Section 8.4
источник
функции void могут возвращать значения void
Малоизвестно, но следующий код подходит
А также следующий странно выглядящий
Зная об этом, можно в некоторых областях воспользоваться. Один пример:
void
функции не могут возвращать значение, но вы также можете не просто ничего не возвращать, потому что они могут быть созданы с непустым. Вместо того, чтобы сохранять значение в локальной переменной, что вызовет ошибкуvoid
, просто верните значение напрямуюисточник
Считываем файл в вектор строк:
istream_iterator
источник
vector<string> V((istream_iterator<string>(cin)), istream_iterator<string>());
- отсутствующие скобки после второго параметраВы можете использовать шаблоны битовых полей.
Я еще не придумал для этого какой-либо цели, но это, черт возьми, меня удивило.
источник
Одна из самых интересных грамматик любых языков программирования.
Три из этих вещей принадлежат друг другу, а две совершенно разные ...
Все, кроме третьего и пятого, определяют
SomeType
объект в стеке и инициализируют его (с помощьюu
в первых двух случаях и конструктором по умолчанию в четвертом. Третий объявляет функцию, которая не принимает параметров и возвращает aSomeType
. Пятый аналогично объявляет функция, которая принимает один параметр по значениюSomeType
указанного типаu
.источник
Избавляемся от форвардных объявлений:
Написание операторов switch с помощью операторов?::
Делаем все в одной строке:
Обнуление структур без memset:
Нормализация / обертывание значений угла и времени:
Назначение референсов:
источник
FStruct s = {};
еще короче.main
? Я бы предложилglobal().main();
и просто забыл о синглтоне ( вы можете просто работать с временным, что продлевает его срок службы )Тернарный условный оператор
?:
требует, чтобы его второй и третий операнды имели "приемлемые" типы (говоря неформально). Но это требование имеет одно исключение (каламбур): второй или третий операнд может быть выражением throw (имеющим типvoid
), независимо от типа другого операнда.Другими словами, можно написать следующие действительно корректные выражения C ++, используя
?:
операторКстати, тот факт, что выражение throw на самом деле является выражением (типа
void
), а не оператором, является еще одной малоизвестной особенностью языка C ++. Это, помимо прочего, означает, что следующий код абсолютно веренхотя в этом нет особого смысла (возможно, в каком-то универсальном коде шаблона это может пригодиться).
источник
Правило доминирования полезно, но малоизвестно. В нем говорится, что даже если в неуникальном пути через решетку базового класса, поиск по имени частично скрытого члена уникален, если член принадлежит виртуальному базовому классу:
Я использовал это, чтобы реализовать поддержку выравнивания, которая автоматически определяет самое строгое выравнивание с помощью правила доминирования.
Это относится не только к виртуальным функциям, но и к именам typedef, статическим / не виртуальным членам и всему остальному. Я видел, как это использовалось для реализации перезаписываемых свойств в метапрограммах.
источник
struct C
в свой пример ...? Приветствия.