Por que std :: min falha quando windows.h está incluído?

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

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

O que o Windows fará se eu incluir o Windows.h? Não consigo usar std::minno Visual Studio 2005. A mensagem de erro é:

error C2589: '(' : illegal token on right side of '::'
error C2059: syntax error : '::'
hidayat
fonte
duplicado de stackoverflow.com/questions/1394132/…
SirDarius de

Respostas:

157

O windows.harquivo de cabeçalho (ou mais corretamente, windef.hque inclui por sua vez) tem macros para mine maxque estão interferindo.

Você deve #define NOMINMAXantes de incluí-lo.

paxdiablo
fonte
28
Uma das razões pelas quais os MACROS são maus. : D
Nawaz de
7
Eu usei um D "NOMINMAX" em todo o projeto
Micka
@Micka: onde você colocou essa opção nas configurações do seu projeto? Tenho que usar a mesma opção, e não sei onde colocar ...
flaviu2
@ flaviu2 afair em um campo de "comandos adicionais" na página onde todos os comandos de compilação estão resumidos. Mas não posso verificar no momento
Micka
pois era para adicionar: #include <algorithm> +
NOMINMAX
91

Não há necessidade de definir nada, apenas ignore a macro usando esta sintaxe:

(std::min)(a, b); // added parentheses around function name
(std::max)(a, b);
PolyMesh
fonte
1
Obrigado, esta é a solução que funcionou para mim. Estou trabalhando em um código em que não posso simplesmente usar NOMINMAX, pois alguma parte do código usa o código de desenho do Windows que precisa de macros.
Mickaël C. Guimarães
Você poderia explicar por que os parênteses em torno da magia podem derrotar a macro do mal !? Legal
Chen OT
1
Não estou totalmente certo sobre toda a mágica sob o capô, mas acredito que o analisador de macro está tentando substituir exatamente "min (", portanto, "min) (" é ignorado pelo analisador de macro. E o nome da função sendo encapsulado com sem sentido () não causa problemas fora das macros.
PolyMesh
1
Solução bacana, mas não resolve o problema de ter uma função com o nome minou max(exemplo de caso de uso: implementação de uma classe que se encaixa no conceito UniformRandomNumberGenerator ).
Nik Bougalis
Por favor, veja a resposta de Erik, acho que é a melhor solução. Menos hacky e mais claro.
PolyMesh
28

Como outros mencionaram, os erros são devido a macros mín / máx que são definidas no (s) cabeçalho (s) do Windows. Existem três maneiras de desativá-los.

1) #define NOMINMAXantes de incluir o cabeçalho, geralmente é uma técnica inadequada de definir macros para afetar os cabeçalhos a seguir;

2) definir NOMINMAXna linha de comando / IDE do compilador. A parte ruim dessa decisão é que se você quiser enviar suas fontes, você precisa avisar os usuários para fazerem o mesmo;

3) simplesmente cancele a definição das macros em seu código antes de serem usadas

#undef min
#undef max

Esta é provavelmente a solução mais portátil e flexível.

Gene Bushuyev
fonte
2
Outro problema com a opção 1 é que ela simplesmente nem sempre funciona. Pode haver outros cabeçalhos do Windows sendo incluídos em outro lugar que realmente precisam, como gdiplus.h. Nesse caso, a opção 3 pode ser sua única esperança.
shawn1874
27

Ainda tenho problemas ocasionalmente com os cabeçalhos das janelas e a definição ampla do projeto NOMINMAX nem sempre parece funcionar. Como alternativa ao uso de parênteses, às vezes deixo o tipo explícito assim:

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

Isso também impede o pré-processador de corresponder mine é indiscutivelmente mais legível do que a solução alternativa entre parênteses.

Erik
fonte
3
Eu concordo, essa é a melhor solução. Eu estava voltando para dar outra resposta quando vi que outra pessoa chegou antes de mim.
PolyMesh
16

Experimente algo assim:

#define NOMINMAX
#include <windows.h>

Por padrão, windows.h define mine maxcomo macros. Quando eles são expandidos, o código que tenta usar std::min(por exemplo) acabará parecendo algo assim:

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

A mensagem de erro informa que isso std::(x)não é permitido.

Jerry Coffin
fonte
5

No meu caso, o projeto não incluiu windows.hou windef.hexplicitamente. Ele estava usando Boost. Então, resolvi o problema indo para o projeto Properties -> C/C++ -> Preprocessore anexando NOMINMAXno Preprocessor Definitions(VS 2013, VS 2015).

Terry
fonte
Para o VS 2015, definir a macro no arquivo não funcionou para mim. Definindo no projeto funcionou.
qqqqq
3

Para pessoas que incluem windows.h, coloque o seguinte nos cabeçalhos afetados:

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

Nos arquivos de origem, apenas #undef min e max.

#include windows headers ...

#undef min
#undef max

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

fonte
2

Para resolver esse problema, acabei de criar um arquivo de cabeçalho chamado fix_minmax.h sem incluir guardas

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

O uso básico é assim.

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

As vantagens dessa abordagem é que ela funciona com todo tipo de arquivo incluído ou parte do código. Isso também economiza seu tempo ao lidar com código ou bibliotecas que dependem de min/ maxmacros

Na linha
fonte
1

Eu presumo que windows.h define min como uma macro, por exemplo, como

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

Isso explicaria a mensagem de erro.

sstn
fonte