... при условии, что существует некоторое максимальное количество гнезд, с которыми вы были бы счастливы остановиться.
Позвольте мне объяснить.
@ torsten-marek прав, что регулярное выражение не может проверять вложенные шаблоны, подобные этому, но возможно определить вложенный шаблон регулярного выражения, который позволит вам захватите вложенные структуры, подобные этому , до некоторой максимальной глубины . Я создал один, чтобы записать комментарии в формате EBNF ( попробуйте здесь ), например:
(* This is a comment (* this is nested inside (* another level! *) hey *) yo *)
Регулярное выражение (для комментариев с одной глубиной ) является следующим:
m{1} = \(+\*+(?:[^*(]|(?:\*+[^)*])|(?:\(+[^*(]))*\*+\)+
Это может быть легко адаптировано для ваших целей, заменив \(+\*+
и \*+\)+
на {
и }
и заменив все между простыми [^{}]
:
p{1} = \{(?:[^{}])*\}
( Вот ссылка , чтобы попробовать это.)
Чтобы вложить, просто разрешите этот шаблон внутри самого блока:
p{2} = \{(?:(?:p{1})|(?:[^{}]))*\}
...or...
p{2} = \{(?:(?:\{(?:[^{}])*\})|(?:[^{}]))*\}
Чтобы найти тройные вложенные блоки, используйте:
p{3} = \{(?:(?:p{2})|(?:[^{}]))*\}
...or...
p{3} = \{(?:(?:\{(?:(?:\{(?:[^{}])*\})|(?:[^{}]))*\})|(?:[^{}]))*\}
Появился четкий шаблон. Чтобы найти комментарии, вложенные в глубину N
, просто используйте регулярное выражение:
p{N} = \{(?:(?:p{N-1})|(?:[^{}]))*\}
where N > 1 and
p{1} = \{(?:[^{}])*\}
Сценарий можно записать для рекурсивного генерации этих регулярных выражений, но это выходит за рамки того, для чего мне это нужно. (Это остается как упражнение для читателя.
Я всегда помню lvalue как значение, которое имеет имя или может быть адресовано. Поскольку x имеет имя, оно передается как lvalue. Цель ссылки на rvalue - разрешить функции полностью clobber-значение любым способом, который он считает нужным. Если мы передадим x по ссылке, как в вашем примере, тогда у нас нет способа узнать, безопасно ли это сделать:
void foo(int &&) {}
void bar(int &&x) {
foo(x);
x.DoSomething(); // what could x be?
};
Выполнение foo(std::move(x));
явно сообщает компилятору, что вы сделали это с помощью x и больше не нуждается в этом. Без этого движения с существующим кодом могут случиться плохие вещи. std::move
является защитой.
std::forward
используется для идеальной пересылки в шаблонах.
Это правило no name ". Внутри bar
, x
имеет имя ... x
. Так что теперь это lvalue. Передача чего-либо функции в качестве ссылки rvalue не делает ее rvalue внутри функции.
Если вы не видите, почему так должно быть, спросите себя: что x
после foo
возвращается? (Помните, что foo
свободно перемещается x
.)
x
по-прежнему является ссылкой rvalue, потому что это то, что объявлено как, но выражение является значением lvalue. Я бы просто изменил & quot; не делает его ссылкой rvalue & quot; to "не делает его rvalue".
– Joseph Mansfield
26 September 2012 в 18:09
Почему он трансформируется в
blockquote>int
один раз внутри тела функции?Это не так; это все еще ссылка на rvalue .
Когда в выражении появляется выражение, это lvalue - даже если это будет ссылка на rvalue . Он может быть преобразован в rvalue , если выражение требует, чтобы (то есть, если его значение необходимо); но он не может быть связан с ссылкой rvalue .
Итак, как вы говорите, чтобы связать его с другой ссылкой rvalue , у вас есть чтобы явно преобразовать его в неназванный rvalue .
std::forward
иstd::move
- это удобные способы сделать это.Кроме того, почему бы не
blockquote>std::move
?Почему бы и нет? Это будет иметь больше смысла, чем
std::forward
, который предназначен для шаблонов, которые не знают, является ли аргумент ссылкой.
rvalue и lvalue являются категориями выражений.
rvalue reference и lvalue reference ] являются категориями ссылок.
Внутри декларации T x&& = <initializer expression>
переменная x как тип T & amp; & amp ;, и она может быть привязана к выражению (the), которое является выражением rvalue . Таким образом, T & amp; & amp; был назван ссылочным типом rvalue , поскольку он ссылается на выражение rvalue .
Внутри декларации T x& = <initializer expression>
переменная x как тип T & amp ; и он может быть связан с выражением (the), которое является выражением lvalue (++). Таким образом, T & amp; был назван ссылочным типом lvalue , поскольку он может ссылаться на выражение lvalue .
Важно, чтобы на C ++ было сделано различие между именования объекта, которое появляется внутри объявления, и когда это выражение появляется внутри выражения.
Когда имя появляется внутри выражения, как в foo(x)
, имя x
само по себе является выражением , называемый id-выражением. По определению и id-выражение всегда является выражением lvalue , а выражения lvalue не могут быть связаны с ссылкой на rvalue .