Mengapa std :: min gagal saat windows.h disertakan?

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

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

Apa yang dilakukan windows jika saya menyertakan Windows.h? Saya tidak dapat menggunakan std::mindi visual studio 2005. Pesan kesalahannya adalah:

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

Jawaban:

157

File windows.hheader (atau lebih tepatnya, windef.hyang disertakan pada gilirannya) memiliki makro mindan maxyang mengganggu.

Anda harus #define NOMINMAXsebelum memasukkannya.

paxdiablo
sumber
28
Salah satu alasan mengapa MACROS itu jahat. : D
Nawaz
7
Saya telah menggunakan proyek-lebar / D "NOMINMAX"
Micka
@ Micka: di mana Anda meletakkan opsi ini di dalam pengaturan proyek Anda? Saya harus menggunakan opsi yang sama, dan saya tidak tahu harus meletakkan di mana ...
flaviu2
@ flaviu2 ada di kolom "perintah tambahan" di halaman tempat semua perintah kompilasi diringkas. Tetapi tidak dapat memeriksa saat ini
Micka
untuk itu harus menambahkan: #include <algorithm> + NOMINMAX
user63898
91

Tidak perlu mendefinisikan apa pun, cukup lewati makro menggunakan sintaks ini:

(std::min)(a, b); // added parentheses around function name
(std::max)(a, b);
PolyMesh
sumber
1
Terima kasih, ini adalah solusi yang berhasil untuk saya. Saya sedang mengerjakan kode di mana saya tidak bisa begitu saja menggunakan NOMINMAX karena beberapa bagian dari kode menggunakan kode gambar dari Windows yang membutuhkan makro.
Mickaël C. Guimarães
Bisakah Anda menjelaskan mengapa tanda kurung di sekitar sihir bisa mengalahkan makro jahat!? Keren
Chen OT
1
Saya tidak sepenuhnya yakin tentang semua keajaiban yang ada di balik terpal, tetapi saya yakin pengurai makro ingin mengganti persis "min (", jadi "min) (" diabaikan oleh pengurai makro. Dan nama fungsi dibungkus dengan maknaless () tidak menyebabkan masalah apa pun di luar makro.
PolyMesh
1
Solusi rapi, tetapi tidak menyelesaikan masalah memiliki fungsi dengan nama minatau max(contoh kasus penggunaan: mengimplementasikan kelas yang sesuai dengan konsep UniformRandomNumberGenerator ).
Nik Bougalis
Silakan lihat jawaban Erik, saya pikir ini adalah solusi yang lebih baik. Lebih sedikit hacky, dan lebih jelas.
PolyMesh
28

Seperti yang disebutkan orang lain, kesalahan disebabkan oleh makro min / maks yang ditentukan di header windows. Ada tiga cara untuk menonaktifkannya.

1) #define NOMINMAXsebelum menyertakan tajuk, ini biasanya merupakan teknik yang buruk dalam menentukan makro untuk memengaruhi tajuk berikut;

2) tentukan NOMINMAXdalam baris perintah kompiler / IDE. Bagian buruk dari keputusan ini adalah jika Anda ingin mengirimkan sumber Anda, Anda perlu memperingatkan pengguna untuk melakukan hal yang sama;

3) cukup batalkan definisi makro dalam kode Anda sebelum digunakan

#undef min
#undef max

Ini mungkin solusi yang paling portabel dan fleksibel.

Gene Bushuyev
sumber
2
Masalah lain dengan opsi 1 adalah bahwa itu tidak selalu berhasil. Mungkin ada header windows lain yang disertakan di tempat lain yang benar-benar membutuhkannya seperti gdiplus.h. Dalam hal ini, opsi 3 mungkin satu-satunya harapan Anda.
shawn1874
27

Saya kadang-kadang masih mengalami masalah dengan header windows dan proyek NOMINMAX sepertinya tidak selalu berfungsi. Sebagai alternatif untuk menggunakan tanda kurung, saya terkadang membuat jenisnya eksplisit seperti:

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

Ini juga menghentikan preprocessor agar tidak mencocokkan ke mindan bisa dibilang lebih mudah dibaca daripada penyelesaian masalah dengan tanda kurung.

Erik
sumber
3
Saya setuju, ini adalah solusi terbaik. Saya baru saja kembali untuk memberikan jawaban lain ketika saya melihat orang lain mengalahkan saya untuk itu.
PolyMesh
16

Coba sesuatu seperti ini:

#define NOMINMAX
#include <windows.h>

Secara default, windows.h mendefinisikan mindan maxsebagai makro. Ketika itu diperluas, kode yang mencoba digunakan std::min(misalnya) akan terlihat seperti ini:

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

Pesan kesalahan memberi tahu Anda bahwa std::(x)itu tidak diperbolehkan.

Jerry Coffin
sumber
5

Dalam kasus saya, proyek tidak menyertakan windows.hatau windef.hsecara eksplisit. Itu menggunakan Boost. Jadi, saya menyelesaikan masalah dengan pergi ke proyek Properties -> C/C++ -> Preprocessor, dan menambahkan NOMINMAXdalam Preprocessor Definitions(VS 2013, VS 2015).

Terry
sumber
Untuk VS 2015, mendefinisikan makro di file tidak berhasil untuk saya. Mendefinisikan dalam proyek berhasil.
qqqqq
3

Untuk orang-orang termasuk windows.h, tempatkan yang berikut ini di header yang terpengaruh:

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

Dalam file sumber, cukup #undef min dan max.

#include windows headers ...

#undef min
#undef max

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

sumber
2

Untuk mengatasi masalah ini saya hanya membuat file header bernama fix_minmax.h tanpa menyertakan penjaga

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

Penggunaan dasar seperti ini.

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

Kelebihan dari pendekatan ini adalah ia bekerja dengan setiap jenis file atau bagian kode yang disertakan. Ini juga menghemat waktu Anda saat berurusan dengan kode atau pustaka yang bergantung pada min/ maxmacro

Di barisan
sumber
1

Saya akan berasumsi windows.h mendefinisikan min sebagai makro, misalnya seperti

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

Itu akan menjelaskan pesan kesalahannya.

sstn
sumber