Например, предварительные декларации и от Раздел Википедии о синтаксисе альтернативных функций:
Тип Ret — это то, что произойдет при добавлении типов Lhs и Rhs. Даже с […] decltype это невозможно:
template<class Lhs, class Rhs> decltype(lhs+rhs) //Not legal C++11 adding_func(const Lhs &lhs, const Rhs &rhs) { return lhs + rhs; }
Это недопустимо в C ++, потому что lhs и rhs еще не определены; они не будут действительными идентификаторами, пока парсер не проанализирует остальную часть прототипа функции.
Когда система находилась под большим давлением памяти, это было понятно (это позволяло делать проходы как потоковые операции). Но почему в наше время (когда на моем смартфоне достаточно ОЗУ для хранения полного исходного кода, полного дерева разбора, а затем и некоторого разумного файла), порядок токенов имеет значение? Есть ли какой-то странный угловой случай в грамматике, который делает невозможным, например, найти конец decltype
нетерминальное производство, если вы не знаете, является ли идентификатор в нем типом или переменной? И в качестве еще одного момента, почему порядок глобальных / пространств имен объявляется вообще?
Редактировать, оказывается, это законно:
class foo {};
foo Foober(int foo) { return ::foo(); }
Если я когда-нибудь столкнусь с этим в дикой природе, то он попадет на The Daily WTF, но это все еще законно.
Это не вопрос емкости, а вопрос обратной совместимости.
Новая версия языка должна сохранять практически все старые функции для обеспечения обратной совместимости. В исходном C ++ тип возвращаемого значения функции-члена не был найден в области видимости класса или функции. Он был найден во вложенном объеме объявления функции. Изменение этого правила может иметь катастрофические последствия для обратной совместимости.
Единственный способ обойти это сделать исключение специально для decltype
аргументы. Но это было бы весьма противоречивым и подверженным ошибкам.
Утверждение «это не разрешено C ++» не совсем точно. Было бы легально, С ++ были lhs
а также rhs
определяется в области, в которой появляется объявление функции. Параметры lhs
а также rhs
не находятся во внешней области видимости, но, безусловно, возможно, что имена находятся в области видимости с некоторым другим объявлением; изменение области действия возвращаемого типа функции могло бы незаметно изменить значение ранее действительных программ.
Область видимости не всегда в лексическом порядке в C ++. Например, внутри тела функции-члена видны все члены, даже те, которые еще не были объявлены. (Ведущий тип возврата также не является частью тела функции-члена, но завершающий возврат есть.)
Есть ли какой-то странный угловой случай в грамматике, который делает невозможным, например, найти конец нетерминального производства decltype, если вы не знаете, является ли идентификатор в нем типом или переменной?
Я так не думаю; круглые скобки decltype
Аргументация должна быть однозначной. Но если вы не знаете, является ли идентификатор шаблоном или нет, это может повлиять на значение <
, >
а также >>
жетоны, способами, которые могут быть действительно тонкими. И незнание, является ли идентификатор типом или функцией, также создает трудности при разборе выражений (даже в C). Так что, безусловно, существуют угловые случаи, в которых важен «вид» имени.
Они должны провести черту между «внутренней» и «внешней» областью видимости где-то. Как вы упомянули, легче найти конец производства, когда идентификаторы в нем могут быть разрешены. Это проще реализовать в компиляторе, и проще последовательно указывать в стандарте языка. Вероятно, поэтому первые компиляторы и сделали так, и язык всегда требует typename
а также template
ключевые слова для разрешения синтаксических неоднозначностей, вызванных неопределенными (вложенными) идентификаторами в расширении шаблона.
И идентификатор никогда не может быть использован до того, как он появится в объявлении, что является прекрасным правилом, помогающим читателям-людям или машинам найти соответствующее объявление. (За исключением случаев между учениками, где для повышения удобства применяется специальный двухпроходный анализ.)
Как только это сделано в одну сторону, обязательство принято, и язык не может измениться. За исключением добавления функции, то есть, и именно так проблема была решена в C ++ 11.
template<class Lhs, class Rhs>
auto adding_func(const Lhs &lhs, const Rhs &rhs) -> decltype(lhs+rhs)
{return lhs + rhs;}
Кстати, есть еще один обходной путь, который они не упоминают:
template<class Lhs, class Rhs>
decltype( declval< Lhs >() + declval< Rhs >() )
adding_func(const Lhs &lhs, const Rhs &rhs) {return lhs + rhs;}
Ваша предпосылка заключается в том, что прямое объявление, предназначенное исключительно для экономии памяти и позволяющее анализировать поток (а не хранить весь исходный файл в памяти), не совсем корректно.
Многие алгоритмы синтаксического анализа, которые мы используем, основаны на прямом проходе, и если вам нужно откатить назад, это может привести к экспоненциальному взрыву во времени анализа (или пространстве) для устранения неоднозначности.
Например — временно принять идентификатор до того, как он объявлен, ничего не зная о том, что это такое, — это значит, что вы должны приступить к анализу, временно учитывая все возможности того, что это такое. (Включая опечатку, но не ограничиваясь ею)