¿Por qué std :: min falla cuando se incluye windows.h?

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

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

¿Qué hace Windows si incluyo Windows.h? No puedo usar std::minen Visual Studio 2005. El mensaje de error es:

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

Respuestas:

156

El windows.harchivo de encabezado (o más correctamente, windef.hque incluye a su vez) tiene macros miny maxque están interfiriendo.

Deberías #define NOMINMAXantes de incluirlo.

paxdiablo
fuente
27
Una de las razones por las que los MACROS son malos. : D
Nawaz
7
He usado un "NOMINMAX" / D para todo el proyecto
Micka
@Micka: ¿dónde pusiste esta opción dentro de la configuración de tu proyecto? Tengo que usar la misma opción, y no sé dónde poner ...
flaviu2
@ flaviu2 afair en un campo de "comandos adicionales" en la página donde se resumen todos los comandos de compilación. Pero no puedo verificar en este momento
Micka
porque fue para agregar: #include <algorithm> + NOMINMAX
user63898
89

No es necesario definir nada, simplemente omita la macro usando esta sintaxis:

(std::min)(a, b); // added parentheses around function name
(std::max)(a, b);
PolyMesh
fuente
1
Gracias, esta es la solución que funcionó para mí. Estoy trabajando en un código en el que no puedo simplemente usar NOMINMAX ya que alguna parte del código usa código de dibujo de Windows que necesita las macros.
Mickaël C. Guimarães
¿Podrías explicar por qué los paréntesis alrededor de la magia pueden derrotar a la macro maligna? Genial
Chen OT
1
No estoy totalmente seguro de toda la magia que hay debajo del capó, pero creo que el analizador de macros busca reemplazar exactamente "min (", por lo que "min) (" es ignorado por el analizador de macros. Y el nombre de la función se envuelve con Significativo () no causa ningún problema fuera de las macros.
PolyMesh
1
Solución ordenada, pero no resuelve el problema de tener una función con el nombre mino max(ejemplo de caso de uso: implementar una clase que se ajuste al concepto UniformRandomNumberGenerator ).
Nik Bougalis
Consulte la respuesta de Erik, creo que es una mejor solución. Menos hacky y más claro.
PolyMesh
28

Como otros mencionaron, los errores se deben a macros mínimas / máximas que se definen en los encabezados de Windows. Hay tres formas de desactivarlos.

1) #define NOMINMAXantes de incluir el encabezado, esta es generalmente una mala técnica para definir macros para afectar los siguientes encabezados;

2) definir NOMINMAXen la línea de comandos del compilador / IDE. La parte mala de esta decisión es que si desea enviar sus fuentes, debe advertir a los usuarios que hagan lo mismo;

3) simplemente anule la definición de las macros en su código antes de que se utilicen

#undef min
#undef max

Esta es probablemente la solución más portátil y flexible.

Gene Bushuyev
fuente
2
Otro problema con la opción 1 es que simplemente no siempre funciona. Es posible que se incluyan otros encabezados de Windows en otros lugares que realmente lo necesiten, como gdiplus.h. En ese caso, la opción 3 podría ser su única esperanza.
shawn1874
27

Todavía tengo problemas ocasionalmente con los encabezados de Windows y la definición amplia del proyecto de NOMINMAX no siempre parece funcionar. Como alternativa al uso de paréntesis, a veces hago explícito el tipo así:

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

Esto también evita que el preprocesador coincida miny posiblemente sea más legible que la solución alternativa entre paréntesis.

Erik
fuente
3
Estoy de acuerdo, esta es la mejor solución. Estaba volviendo para dar otra respuesta cuando vi que alguien más se me adelantó.
PolyMesh
16

Intente algo como esto:

#define NOMINMAX
#include <windows.h>

De forma predeterminada, windows.h define miny maxcomo macros. Cuando se expanden, el código que intenta usar std::min(por ejemplo) terminará luciendo algo como esto:

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

El mensaje de error le dice que std::(x)no está permitido.

Jerry Coffin
fuente
5

En mi caso, el proyecto no incluía windows.hni windef.hexplícitamente. Estaba usando Boost. Entonces, resolví el problema yendo al proyecto Properties -> C/C++ -> Preprocessory agregando NOMINMAXel Preprocessor Definitions(VS 2013, VS 2015).

Terry
fuente
Para VS 2015, definir la macro en el archivo no funcionó para mí. Definir en el proyecto funcionó.
qqqqq
3

Para las personas que incluyan windows.h, coloque lo siguiente en los encabezados afectados:

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

En los archivos de origen solo #undef min y max.

#include windows headers ...

#undef min
#undef max

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

fuente
2

Para resolver este problema, solo creo un archivo de encabezado llamado fix_minmax.h sin incluir guardias

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

El uso básico es así.

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

Las ventajas de este enfoque es que funciona con todo tipo de archivo incluido o parte de código. Esto también le ahorra tiempo al tratar con códigos o bibliotecas que dependen de min/ maxmacros

En línea
fuente
1

Asumiría que windows.h define min como una macro, por ejemplo, como

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

Eso explicaría el mensaje de error.

sstn
fuente