Правила поиска аргументов в C ++. - PullRequest
0 голосов
/ 04 февраля 2011

В последнее время по ADL были некоторые вопросы по SO, которые заставили меня задуматься. В принципе, я запутался, какие заголовочные файлы компилятор может искать при выполнении ADL? Это только те, которые включены в код пользователя или могут включать в себя другие файлы заголовков, в которых используется то же пространство имен, которое используется в коде пользователя? Например. std Пространство имен охватывает несколько файлов заголовков. Тем не менее, я могу включить только часть этого. Теперь, если я определю функцию, которой нет в этом подмножестве заголовочных файлов, но есть в пространстве имен std (в файле, который я не включил), будет ли это все еще двусмысленным вызовом? Я получил это сомнение в основном из-за обсуждения этого вопроса

Ответы [ 5 ]

4 голосов
/ 04 февраля 2011

Вот как это работает ... Есть 3 основных шага для компиляции исходного кода в исполняемый файл:

  1. предварительная обработка
  2. компиляция
  3. связывание

В C ++ эти шаги перекрываются нулями.Директивы include являются директивами препроцессора и поэтому происходят перед компиляцией.Создание шаблона является частью компиляции, поэтому это происходит после предварительной обработки.Компиляторы не ищут ничего за пределами текущей единицы перевода.Таким образом, нет, ADL, событие времени компиляции, не может искать заголовки, которые там не включены.

Проблема с вашим кодом, связанным в комментарии к Buzz, состоит в том, что вы не можете знать, какие заголовки включены или нетстандартные заголовки.(Ну, вы можете знать, посмотрите ли вы на них, чтобы узнать, но стандарт не говорит.) Любой из ваших заголовков мог, и, очевидно, включал <algorithm>.Как только это произойдет:

http://www2.roguewave.com/support/docs/leif/sourcepro/html/stdlibref/merge.html

Ваша версия становится неоднозначной с одним из определений в namespace std из-за ADL.

1 голос
/ 04 февраля 2011

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

Это означает, что теоретически только включение <vector> может сделать доступным std::map.

Это прискорбно, потому что

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

  2. Вы можете получить проблемы с поиском из-за ADL, если любое из ваших имен также является именами в std. Это также может проявиться как проблема переносимости.

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

Поэтому ADL МОЖЕТ посмотреть все возможные стандартные заголовки, но вы не можете на это рассчитывать.

1 голос
/ 04 февраля 2011

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

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

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

1 голос
/ 04 февраля 2011

Нет.Пока вы избегаете включения заголовка, который содержит определение (или включения заголовка, который включает другой заголовок, который содержит определение), не будет никакого неоднозначного вызова.Вы можете определить свой собственный iostream, string, vector и т. Д., Пока стандартная версия C ++ не включена (несмотря на то, что вы, возможно, включили другие части пространства имен std).

0 голосов
/ 04 февраля 2011

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

...