Tại sao std :: min không thành công khi có windows.h?


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

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

Windows đang làm gì nếu tôi bao gồm Windows.h? Tôi không thể sử dụng std::mintrong visual studio 2005. Thông báo lỗi là:

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

Câu trả lời:


155

Tệp windows.htiêu đề (hay nói đúng hơn windef.hlà nó bao gồm lần lượt) có các macro minvà các macro maxgây nhiễu.

Bạn nên #define NOMINMAXđưa nó vào trước.


27
Một trong những lý do tại sao MACROS là xấu. : D
Nawaz

7
Tôi đã sử dụng toàn bộ dự án / D "NOMINMAX"
Micka,

@Micka: bạn đã đặt tùy chọn này ở đâu trong cài đặt dự án của mình? Tôi phải sử dụng tùy chọn tương tự, và tôi không biết nơi để đặt ...
flaviu2

@ flaviu2 afair trong trường "lệnh bổ sung" trên trang nơi tất cả các lệnh biên dịch được tóm tắt. Nhưng không thể kiểm tra vào lúc này
Micka

vì nó đã được thêm: #include <algorithm> + NOMINMAX
user63898

89

Không cần xác định bất cứ điều gì, chỉ cần bỏ qua macro bằng cú pháp sau:

(std::min)(a, b); // added parentheses around function name
(std::max)(a, b);

1
Cảm ơn bạn, đây là giải pháp đã làm việc cho tôi. Tôi đang làm việc trên một mã mà tôi không thể đơn giản sử dụng NOMINMAX vì một số phần của mã sử dụng mã vẽ từ Windows cần macro.
Mickaël C. Guimarães

Bạn có thể giải thích tại sao dấu ngoặc đơn xung quanh phép thuật có thể đánh bại vĩ mô ma quỷ !? Cool
Chen OT

1
Tôi không hoàn toàn chắc chắn về tất cả những điều kỳ diệu bên dưới, nhưng tôi tin rằng trình phân tích cú pháp macro đang tìm cách thay thế chính xác "min (", vì vậy "min) (" bị trình phân tích cú pháp macro bỏ qua. Và tên hàm được bao gồm vô nghĩa () 's không gây ra bất kỳ vấn đề bên ngoài của macro.
PolyMesh

1
Giải pháp gọn gàng, nhưng không giải quyết được vấn đề có một hàm có tên minhoặc max(trường hợp sử dụng mẫu: triển khai một lớp phù hợp với khái niệm UniformRandomNumberGenerator ).
Nik Bougalis

Hãy xem câu trả lời của Erik, tôi nghĩ đó là một giải pháp tốt hơn. Ít hack và rõ ràng hơn.
PolyMesh

28

Như những người khác đã đề cập, lỗi là do macro tối thiểu / tối đa được xác định trong (các) tiêu đề cửa sổ. Có ba cách để vô hiệu hóa chúng.

1) #define NOMINMAXtrước khi bao gồm tiêu đề, đây thường là một kỹ thuật xác định macro không tốt để ảnh hưởng đến các tiêu đề sau;

2) xác định NOMINMAXtrong dòng lệnh của trình biên dịch / IDE. Phần tồi tệ của quyết định này là nếu bạn muốn gửi các nguồn của mình, bạn cần phải cảnh báo những người dùng làm điều tương tự;

3) chỉ cần hoàn tác các macro trong mã của bạn trước khi chúng được sử dụng

#undef min
#undef max

Đây có lẽ là giải pháp linh hoạt và linh hoạt nhất.


2
Một vấn đề khác với tùy chọn 1 là nó không phải lúc nào cũng hoạt động. Có thể có các tiêu đề cửa sổ khác được đưa vào ở những nơi thực sự cần nó, chẳng hạn như gdiplus.h. Trong trường hợp đó, lựa chọn 3 có thể là hy vọng duy nhất của bạn.
shawn1874

27

Đôi khi tôi vẫn gặp sự cố với tiêu đề cửa sổ và định nghĩa rộng của dự án NOMINMAX dường như không phải lúc nào cũng hoạt động. Để thay thế cho việc sử dụng dấu ngoặc đơn, đôi khi tôi đặt kiểu rõ ràng như vậy:

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

Điều này cũng ngăn bộ xử lý trước so khớp với minvà được cho là dễ đọc hơn so với cách giải quyết dấu ngoặc đơn.


3
Tôi đồng ý, đây là giải pháp tốt nhất. Tôi chỉ định quay lại để đưa ra một câu trả lời khác thì tôi thấy có người khác đã đánh tôi.
PolyMesh

16

Hãy thử một cái gì đó như sau:

#define NOMINMAX
#include <windows.h>

Theo mặc định, windows.h định nghĩa minmaxdưới dạng macro. Khi chúng được mở rộng, mã cố gắng sử dụng std::min(ví dụ) sẽ kết thúc trông giống như sau:

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

Thông báo lỗi cho bạn biết điều đó std::(x)không được phép.


5

Trong trường hợp của tôi, dự án không bao gồm windows.hhoặc windef.hrõ ràng. Nó đã được sử dụng Boost. Vì vậy, tôi đã giải quyết vấn đề bằng cách đi tới dự án Properties -> C/C++ -> Preprocessorvà bổ sung NOMINMAXtrong Preprocessor Definitions(VS 2013, VS 2015).


Đối với VS 2015, việc xác định macro trong tệp không hoạt động với tôi. Xác định trong dự án đã hoạt động.
qqqqq

3

Đối với những người bao gồm windows.h, hãy đặt những điều sau vào các tiêu đề có hiệu lực:

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

Trong tệp nguồn, chỉ cần #undef tối thiểu và tối đa.

#include windows headers ...

#undef min
#undef max

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


2

Để giải quyết vấn đề này, tôi chỉ cần tạo tệp tiêu đề có tên fix_minmax.h mà không bao gồm bảo vệ

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

Cách sử dụng cơ bản là như thế này.

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

Ưu điểm của phương pháp này là nó hoạt động với mọi loại tệp hoặc một phần mã được bao gồm. Điều này cũng tiết kiệm thời gian của bạn khi xử lý mã hoặc thư viện phụ thuộc vào min/ maxmacro


1

Tôi giả sử windows.h xác định min là một macro, ví dụ như

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

Điều đó sẽ giải thích thông báo lỗi.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.