Dlaczego std :: min nie działa, gdy dołączony jest windows.h?

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

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

Co robi Windows, jeśli dołączę Windows.h? Nie mogę używać std::minw programie Visual Studio 2005. Komunikat o błędzie:

error C2589: '(' : illegal token on right side of '::'
error C2059: syntax error : '::'
hidayat
źródło

Odpowiedzi:

158

windows.hPlik nagłówka (lub bardziej poprawnie, windef.hże zawiera z kolei) ma dla makr mini maxktóre zakłócają.

Powinieneś #define NOMINMAXprzed dołączeniem go.

paxdiablo
źródło
29
Jeden z powodów, dla których MAKRA są złe. : D
Nawaz,
7
Użyłem całego projektu / D „NOMINMAX”
Micka
@Micka: gdzie umieściłeś tę opcję w ustawieniach projektu? Muszę skorzystać z tej samej opcji i nie wiem, gdzie umieścić ...
flaviu2
@ flaviu2 afair w polu „dodatkowe polecenia” na stronie, gdzie podsumowane są wszystkie polecenia kompilacji. Ale w tej chwili nie mogę sprawdzić
Micka
bo miał dodać: #include <algorithm> + NOMINMAX
user63898
92

Nie musisz niczego definiować, po prostu pomiń makro, używając następującej składni:

(std::min)(a, b); // added parentheses around function name
(std::max)(a, b);
PolyMesh
źródło
1
Dziękuję, to rozwiązanie zadziałało dla mnie. Pracuję nad kodem, w którym nie mogę po prostu użyć NOMINMAX, ponieważ część kodu używa kodu rysującego z systemu Windows, który wymaga makr.
Mickaël C. Guimarães
1
Czy możesz wyjaśnić, dlaczego nawiasy wokół magii mogą pokonać złe makro !? Cool
Chen OT
2
Nie jestem całkowicie pewien całej magii kryjącej się pod maską, ale wydaje mi się, że parser makr chce zastąpić dokładnie „min (”, więc „min) (” jest ignorowane przez parser makr. A nazwa funkcji jest opakowana sensless () nie powoduje żadnych problemów poza makrami
PolyMesh
1
Zgrabne rozwiązanie, ale nie rozwiązuje problemu posiadania funkcji o nazwie minlub max(przykład użycia: implementacja klasy, która pasuje do koncepcji UniformRandomNumberGenerator ).
Nik Bougalis
Proszę zobaczyć odpowiedź Erika, myślę, że to lepsze rozwiązanie. Mniej hacky i wyraźniejszy.
PolyMesh
28

Jak wspominali inni, błędy wynikają z makr min / max, które są zdefiniowane w nagłówkach Windows. Istnieją trzy sposoby ich wyłączenia.

1) #define NOMINMAXprzed dołączeniem nagłówka jest to ogólnie zła technika definiowania makr, aby wpływać na następujące nagłówki;

2) zdefiniuj NOMINMAXw wierszu poleceń kompilatora / IDE. Zła część tej decyzji polega na tym, że jeśli chcesz wysłać swoje źródła, musisz ostrzec użytkowników, aby zrobili to samo;

3) po prostu cofnij definicję makr w kodzie, zanim zostaną użyte

#undef min
#undef max

Jest to prawdopodobnie najbardziej przenośne i elastyczne rozwiązanie.

Gene Bushuyev
źródło
2
Innym problemem związanym z opcją 1 jest to, że po prostu nie zawsze działa. Mogą istnieć inne nagłówki systemu Windows, które są dołączone w innym miejscu, które faktycznie ich potrzebuje, na przykład gdiplus.h. W takim przypadku jedyną nadzieją może być opcja 3.
shawn1874
27

Nadal mam czasami problemy z nagłówkami systemu Windows, a definicja NOMINMAX w całym projekcie nie zawsze działa. Zamiast używać nawiasów, czasami określam typ jawnie w następujący sposób:

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

To również zapobiega dopasowywaniu się preprocesora do mini jest prawdopodobnie bardziej czytelne niż obejście z nawiasami.

Erik
źródło
3
Zgadzam się, to najlepsze rozwiązanie. Właśnie wracałem, by udzielić kolejnej odpowiedzi, kiedy zobaczyłem, że ktoś inny mnie pobił.
PolyMesh
16

Spróbuj czegoś takiego:

#define NOMINMAX
#include <windows.h>

Domyślnie windows.h definiuje mini maxjako makra. Kiedy te zostaną rozwinięte, kod, który próbuje użyć std::min(na przykład), będzie wyglądał mniej więcej tak:

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

Komunikat o błędzie informuje, że std::(x)nie jest to dozwolone.

Jerry Coffin
źródło
5

W moim przypadku projekt nie zawierał windows.hani windef.hwyraźnie. Używał Boost. Tak, problem został rozwiązany, przechodząc do projektu Properties -> C/C++ -> Preprocessor, a dodanie NOMINMAXw Preprocessor Definitions(VS 2013, VS 2015).

Terry
źródło
W VS 2015 definiowanie makra w pliku nie działało. Definiowanie w projekcie zadziałało.
qqqqq
3

Dla osób, które zawierają windows.h, umieść następujące nagłówki:

#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")

W plikach źródłowych tylko #undef min i max.

#include windows headers ...

#undef min
#undef max

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

źródło
2

Aby rozwiązać ten problem, po prostu utworzę plik nagłówkowy o nazwie fix_minmax.h bez włączonych zabezpieczeń

#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;

Podstawowe użycie jest takie.

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

Zaletą tego podejścia jest to, że działa z każdym rodzajem dołączonego pliku lub części kodu. Oszczędza to również czas podczas pracy z kodem lub bibliotekami zależnymi od min/ maxmacros

Inline
źródło
1

Zakładam, że windows.h definiuje min jako makro, np. Jak

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

To wyjaśniałoby komunikat o błędzie.

sstn
źródło