Pourquoi std :: min échoue-t-il lorsque windows.h est inclus?

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

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

Que fait Windows si j'inclus Windows.h? Je ne peux pas utiliser std::mindans Visual Studio 2005. Le message d'erreur est:

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

Réponses:

158

Le windows.hfichier d'en-tête (ou plus correctement, windef.hqu'il inclut à son tour) a des macros pour minet maxqui interfèrent.

Vous devriez #define NOMINMAXavant de l'inclure.

paxdiablo
la source
29
Une des raisons pour lesquelles les MACROS sont maléfiques. : D
Nawaz
7
J'ai utilisé un projet / D "NOMINMAX"
Micka
@Micka: où avez-vous mis cette option dans les paramètres de votre projet? Je dois utiliser la même option, et je ne sais pas où mettre ...
flaviu2
@ flaviu2 afair dans un champ "commandes supplémentaires" sur la page où toutes les commandes de compilation sont résumées. Mais je ne peux pas vérifier pour le moment
Micka
car il
fallait
92

Pas besoin de définir quoi que ce soit, contournez simplement la macro en utilisant cette syntaxe:

(std::min)(a, b); // added parentheses around function name
(std::max)(a, b);
PolyMesh
la source
1
Merci, c'est la solution qui a fonctionné pour moi. Je travaille sur un code où je ne peux pas simplement utiliser NOMINMAX car une partie du code utilise le code de dessin de Windows qui a besoin des macros.
Mickaël C. Guimarães
1
Pouvez-vous expliquer pourquoi les parenthèses autour de la magie peuvent vaincre la mauvaise macro !? Cool
Chen OT
2
Je ne suis pas tout à fait sûr de toute la magie sous le capot, mais je pense que l'analyseur de macros cherche à remplacer exactement "min (", donc "min) (" est ignoré par l'analyseur de macro. Et le nom de la fonction est entouré par signifiant () ne pose aucun problème en dehors des macros.
PolyMesh
1
Solution soignée, mais ne résout pas le problème d'avoir une fonction avec le nom minou max(exemple de cas d'utilisation: implémentation d'une classe qui s'inscrit dans le concept UniformRandomNumberGenerator ).
Nik Bougalis
S'il vous plaît voir la réponse d'Erik, je pense que c'est une meilleure solution. Moins hacky et plus clair.
PolyMesh
28

Comme d'autres l'ont mentionné, les erreurs sont dues aux macros min / max qui sont définies dans les en-têtes Windows. Il existe trois façons de les désactiver.

1) #define NOMINMAXavant d'inclure l'en-tête, c'est généralement une mauvaise technique de définition de macros afin d'affecter les en-têtes suivants;

2) définir NOMINMAXdans la ligne de commande du compilateur / IDE. Le mauvais côté de cette décision est que si vous souhaitez expédier vos sources, vous devez avertir les utilisateurs de faire de même;

3) Annulez simplement les macros dans votre code avant qu'elles ne soient utilisées

#undef min
#undef max

C'est probablement la solution la plus portable et la plus flexible.

Gene Bushuyev
la source
2
Un autre problème avec l'option 1 est qu'elle ne fonctionne tout simplement pas toujours. Il peut y avoir d'autres en-têtes de fenêtres inclus ailleurs qui en ont réellement besoin, comme gdiplus.h. Dans ce cas, l'option 3 pourrait être votre seul espoir.
shawn1874
27

J'ai encore des problèmes avec les en-têtes Windows et la définition de NOMINMAX à l'échelle du projet ne semble pas toujours fonctionner. Au lieu d'utiliser des parenthèses, je rends parfois le type explicite comme ceci:

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

Cela empêche également le préprocesseur de correspondre à minet est sans doute plus lisible que la solution de contournement entre parenthèses.

Erik
la source
3
Je suis d'accord, c'est la meilleure solution. Je revenais juste pour donner une autre réponse quand j'ai vu que quelqu'un d'autre m'avait battu.
PolyMesh
16

Essayez quelque chose comme ceci:

#define NOMINMAX
#include <windows.h>

Par défaut, windows.h définit minet en maxtant que macros. Lorsque ceux-ci sont développés, le code qui essaie d'utiliser std::min(par exemple) finira par ressembler à ceci:

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

Le message d'erreur vous indique que ce std::(x)n'est pas autorisé.

Jerry Coffin
la source
5

Dans mon cas, le projet n'a pas inclus windows.hou windef.hexplicitement. Il utilisait Boost. J'ai donc résolu le problème en accédant au projet Properties -> C/C++ -> Preprocessoret en ajoutant NOMINMAXdans le Preprocessor Definitions(VS 2013, VS 2015).

Terry
la source
Pour VS 2015, la définition de la macro dans le fichier n'a pas fonctionné pour moi. La définition dans le projet a fonctionné.
qqqqq
3

Pour les personnes incluant windows.h, mettez ce qui suit dans les en-têtes affectés:

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

Dans les fichiers source, juste #undef min et max.

#include windows headers ...

#undef min
#undef max

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

la source
2

Pour résoudre ce problème, je crée simplement un fichier d'en-tête nommé fix_minmax.h sans inclure les gardes

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

L'utilisation de base est comme ça.

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

L'avantage de cette approche est qu'elle fonctionne avec chaque type de fichier inclus ou partie de code. Cela vous fait également gagner du temps lorsque vous traitez du code ou des bibliothèques qui dépendent de min/ maxmacros

En ligne
la source
1

Je suppose que windows.h définit min comme une macro, par exemple comme

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

Cela expliquerait le message d'erreur.

sstn
la source