Чому невдало std :: min при включенні windows.h?


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

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

Що робити Windows, якщо я включаю Windows.h? Я не можу використовувати std::minу візуальній студії 2005. Повідомлення про помилку:

error C2589: '(' : illegal token on right side of '::'
error C2059: syntax error : '::'

Відповіді:


156

Файл windows.hзаголовка (або правильніше, windef.hщо він включає в свою чергу) має макроси minта maxякі заважають.

Ви повинні #define NOMINMAXперед тим, як включити його.


27
Одна з причин, чому MACROS - це зло. : D
Наваз

7
Я використовував проект / D "NOMINMAX"
Micka

@Micka: куди ти поставив цю опцію в налаштуваннях свого проекту? Я повинен використовувати той самий варіант, і я не знаю, куди поставити ...
flaviu2

@ flaviu2 afair у полі "додаткові команди" на сторінці, де всі команди компіляції узагальнені. Але наразі не можете перевірити
Micka

для цього потрібно було додати: #include <алгоритм> + NOMINMAX
user63898

90

Не потрібно нічого визначати, просто обійдіть макрос за допомогою цього синтаксису:

(std::min)(a, b); // added parentheses around function name
(std::max)(a, b);

1
Дякую, це рішення, яке працювало на мене. Я працюю над кодом, де я не можу просто використовувати NOMINMAX, оскільки частина частини коду використовує малюнок коду з Windows, який потребує макросів.
Mickaël C. Guimarães

Чи можете ви пояснити, чому дужки навколо магії можуть перемогти злий макрос? Cool
Chen OT

1
Я не повністю впевнений у всій магії під кришкою, але я вважаю, що макроаналізатор прагне замінити саме "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 полягає в тому, що він просто не завжди працює. Можливо, ще в інших місцях будуть включені заголовки Windows, які фактично потребують цього, наприклад, gdiplus.h. У такому випадку варіант 3 може бути вашою єдиною надією.
shawn1874

27

У мене все ще виникають проблеми з заголовками Windows і визначення проекту 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/ maxмакросів


1

Я припускаю, що windows.h визначає min як макрос, наприклад, як

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

Це пояснило б повідомлення про помилку.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.