Почему std :: min не работает, когда включен windows.h?

109
#include <algorithm>
#include <Windows.h>

int main()
{
    int k = std::min(3, 4);
    return 0;
}

Что будут делать окна, если я включу Windows.h? Я не могу использовать std::minв Visual Studio 2005. Сообщение об ошибке:

error C2589: '(' : illegal token on right side of '::'
error C2059: syntax error : '::'
хидайят
источник
дубликат stackoverflow.com/questions/1394132/…
SirDarius

Ответы:

158

windows.hЗаголовка файла (или более правильно, windef.hчто она включает в себя , в свою очередь) имеет макросы minиmax которые мешают.

Вы должны #define NOMINMAXперед его включением.

Paxdiablo
источник
29
Одна из причин, почему МАКРОСЫ злы. : D
Наваз
7
Я использовал проект-широкий / D "NOMINMAX"
Micka
@Micka: где вы поместили эту опцию в настройках вашего проекта? Я должен использовать тот же вариант, и я не знаю, куда его поставить ...
flaviu2
@ flaviu2 в поле «дополнительные команды» на странице, где суммированы все команды компиляции. Но не может проверить , на данный момент
Micka
для этого нужно было добавить: #include <алгоритм> + NOMINMAX
user63898
92

Не нужно ничего определять, просто пропустите макрос, используя этот синтаксис:

(std::min)(a, b); // added parentheses around function name
(std::max)(a, b);
PolyMesh
источник
1
Спасибо, это решение, которое у меня сработало. Я работаю над кодом, в котором я не могу просто использовать NOMINMAX, поскольку некоторая часть кода использует код рисования из Windows, которому нужны макросы.
Микаэль С. Гимарайнш
1
Не могли бы вы объяснить, почему скобки вокруг магии могут победить злой макрос !? Cool
Chen OT
2
Я не совсем уверен во всей магии, скрытой под капотом, но я считаю, что анализатор макросов пытается заменить именно «min (», поэтому «min) (» игнорируется анализатором макросов. И имя функции, заключенное в бессмысленный () не вызывает никаких проблем, кроме макросов.
PolyMesh
1
Замечательное решение, но не решает проблему наличия функции с именем minили max(пример использования: реализация класса, который вписывается в концепцию UniformRandomNumberGenerator ).
Ник Бугалис
См. Ответ Эрика, я думаю, что это лучшее решение. Менее хакерский и более понятный.
PolyMesh
28

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

1) #define NOMINMAXперед включением заголовка это обычно плохой метод определения макросов, чтобы повлиять на следующие заголовки;

2) определить NOMINMAXв командной строке компилятора / IDE. Плохая часть этого решения состоит в том, что если вы хотите отправить свои источники, вам нужно предупредить пользователей, чтобы они сделали то же самое;

3) просто отмените определение макросов в своем коде перед их использованием

#undef min
#undef max

Это, наверное, самое портативное и гибкое решение.

Гена Бушуев
источник
2
Еще одна проблема с вариантом 1 заключается в том, что он не всегда работает. Могут быть включены другие заголовки окон, которые действительно нуждаются в этом, например gdiplus.h. В таком случае вариант 3 может быть вашей единственной надеждой.
shawn1874
27

Иногда у меня все еще возникают проблемы с заголовками окон, и широкое определение NOMINMAX не всегда работает. В качестве альтернативы круглым скобкам я иногда делаю тип явным:

int k = std::min<int>(3, 4);

Это также предотвращает сопоставление препроцессора с minи, возможно, более читабельно, чем обходной путь в круглых скобках.

Эрик
источник
3
Согласен, это лучшее решение. Я как раз возвращался, чтобы дать еще один ответ, когда увидел, что кто-то меня опередил.
PolyMesh
16

Попробуйте что-то вроде этого:

#define NOMINMAX
#include <windows.h>

По умолчанию windows.h определяет minи maxкак макросы. Когда они расширяются, код, который пытается использовать std::min(например), в конечном итоге будет выглядеть примерно так:

int k = std::(x) < (y) ? (x) : (y);

Сообщение об ошибке сообщает вам, что std::(x)это запрещено.

Джерри Гроб
источник
5

В моем случае проект не был включен windows.hили windef.hявно. Он использовал Boost. Итак, я решил проблему, перейдя в проект Properties -> C/C++ -> Preprocessorи добавив NOMINMAXв Preprocessor Definitions(VS 2013, VS 2015).

Терри
источник
Для VS 2015 определение макроса в файле у меня не сработало. Определение в проекте сработало.
qqqqq
3

Для людей, использующих windows.h, вставьте в обработанные заголовки следующее:

#include windows headers ...

pragma push_macro("min")
pragma push_macro("max")
#undef min
#undef max

#include headers expecting std::min/std::max ...

...

pragma pop_macro("min")
pragma pop_macro("max")

В исходных файлах просто #undef min и max.

#include windows headers ...

#undef min
#undef max

#include headers expecting std::min/std::max ...

источник
2

Чтобы решить эту проблему, я просто создаю файл заголовка с именем fix_minmax.h без включения охранников.

#ifdef max
    #undef max
#endif

#ifdef min
    #undef min
#endif

#ifdef MAX
    #undef MAX
#endif
#define MAX max

#ifdef MIN
   #undef MIN
#endif
#define MIN min

#include <algorithm>
using std::max;
using std::min;

Основное использование похоже на это.

// Annoying third party header with min/max macros
#include "microsoft-mega-api.h"
#include "fix_minmax.h"

Плюсы этого подхода в том, что он работает со всеми типами включаемых файлов или частей кода. Это также экономит ваше время при работе с кодом или библиотеками, которые зависят от min/ maxmacros.

В линию
источник
1

Я предполагаю, что windows.h действительно определяет min как макрос, например как

#define min(a,b)  ((a < b) ? a : b)

Это объяснило бы сообщение об ошибке.

sstn
источник