Почему std::max и std::min все еще можно использовать, даже если я не #include ‹algorithm›?

#include <iostream>

int main()
{
   int value1 = 1, value2 = 10;
   std::cout << "Min = " << std::min(value1,value2) <<std::endl;
   std::cout << "Max = " << std::max(value1,value2)<< std::endl;              
} 

Насколько я знаю, функции min и max определены в <algorithm>.

Если я не сказал препроцессору включить <algorithm>, почему код все еще работает?


person Anthony    schedule 11.11.2013    source источник
comment
потому что вы находитесь под пространством имен std? (используя пространство имен std;)   -  person John Yang    schedule 11.11.2013
comment
Вы уверены, что это std версии min и max? Попробуйте дать им полную квалификацию.   -  person paddy    schedule 11.11.2013
comment
Возможно, что iostream включает в себя algorithm, но не стоит рассчитывать на такое поведение.   -  person Retired Ninja    schedule 11.11.2013
comment
Я изменил коды, и я был уверен, что на этот раз набрал std::min и std::max, результаты те же, они все еще работают.   -  person Anthony    schedule 11.11.2013


Ответы (3)


Скорее всего, что-то внутри iostream прямо или косвенно включает какой-то другой заголовок, определяющий std::min и std::max. (Возможно, был включен сам algorithm. Возможно, какой-то внутренний заголовок, который используется для реализации вашей стандартной библиотеки C++.)

Не следует полагаться на такое поведение. Включите algorithm, если вы хотите использовать std::min и std::max.

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

Напомним, однако, что #include выполняет текстовую замену. Когда строка #include обрабатывается, она удаляется из файла .cpp и заменяется содержимым файла, на который она указывала.

У большинства компиляторов есть возможность выводить результаты работы препроцессора, чтобы вы могли отследить, что в том числе и что. В своем комментарии к ответу kmort вы сказали, что используете Visual Studio Express. Командная строка для предварительной обработки файла в файл использование компилятора Visual C++ — это cl /P foo.cpp. Используя этот вывод, мы можем обнаружить, что определение std::max исходит из заголовка xutility, специфичного для реализации. (Размещение курсора внутри текста «std: max» и нажатие F12 в Visual Studio еще быстрее. :-])

kmort также упомянул компилятор /showIncludes. выключатель. Используя это, мы можем легко отследить цепочку включения. Вот уменьшенный результат моего прогона.

Note: including file: C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\INCLUDE\iostream
Note: including file:  C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\INCLUDE\istream
Note: including file:   C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\INCLUDE\ostream
Note: including file:    C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\INCLUDE\ios
Note: including file:     C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\INCLUDE\xlocnum
Note: including file:      C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\INCLUDE\streambuf
Note: including file:       C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\INCLUDE\xiosbase
Note: including file:        C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\INCLUDE\xlocale
Note: including file:         C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\INCLUDE\stdexcept
Note: including file:          C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\INCLUDE\xstring
Note: including file:           C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\INCLUDE\xmemory0
Note: including file:            C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\INCLUDE\xutility
person chwarr    schedule 11.11.2013

Какой компилятор вы используете?

Я видел, что компиляторы до этого несколько «снисходительны» к общим элементам, которые определены в libc или libstdc++. Он вытянет ссылки для вас. Другими словами, вам не нужно указывать ему ссылку на него или включать заголовок. Это просто работает. Хотя я не ожидал такого от min() и max(), в этом нет ничего удивительного.

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

person kmort    schedule 11.11.2013
comment
Visual Studio Express 2012 - person Anthony; 11.11.2013
comment
Что ж, поскольку вы убедились, что это не какой-то макрос, вы можете проверить, действительно ли iostream включает algorithm или нет, с помощью аргумента командной строки /showIncludes для компилятора C++. msdn.microsoft.com/en-us /библиотека/vstudio/ - person kmort; 11.11.2013
comment
Я отредактировал пост и изменил max и min на std::max и std::min. Он все еще работает. - person Anthony; 11.11.2013
comment
Поскольку вы используете Visual Studio, cl.exe /P foo.cpp создаст файл foo.i, содержащий полный предварительно обработанный текст. Для меня, просмотрев строку 47885, вы увидите определение std::max из заголовка xutility, специфичного для реализации. Просматривая файл в обратном порядке, выясните, какая последовательность операторов #include осталась для вас в качестве упражнения. Возможно, ничего не стоит то, что ваш 8-строчный файл .cpp был предварительно обработан примерно до 82 000 строк. - person chwarr; 11.11.2013
comment
@kmort, это крутая функция, которой я никогда раньше не пользовался. Я всегда делал это трудным путем. Я узнаю что-то новое каждый день. - person chwarr; 11.11.2013
comment
Мне трудно поверить, что это когда-либо было результатом того, что компиляторы «прощающе вытаскивают ссылки для вас», а не косвенное включение. И последний был назван виновником в данном случае, вопреки вашим ожиданиям. - person underscore_d; 18.07.2017

Просто чтобы добавить вышеупомянутые разговоры, я недавно наткнулся на подобную проблему. Если вы выполняете вызовы min/max без включения заголовка algorithm, он все равно будет работать нормально.

std::min(value1, value2)

Но если вы выполните его в списке инициализаторов (поместите все переменные между {...}), как показано ниже,

std::min({value1, value2, value3})

компилятор выдает ошибку несоответствия аргументов. Скорее всего, это связано с тем, что функция переопределения не смогла поймать template constexpr T max (initializer_list il, Compare comp), которая должна быть определена только внутри algorithm.h. Как ответили другие, базовый template constexpr const T& max (const T& a, const T& b) мог быть включен где-то внутри iostream. Но я не думаю, что весь заголовочный файл algorithm был включен, потому что если бы он был, приведенный выше фрагмент тоже должен был работать.

person Siva Ramakrishnan    schedule 25.01.2021