轉至 http://blog.csdn.net/rnamatrix/article/details/5765462
今天在使用limits中的numeric_limits類模板函數max和min時,編譯出現了一個錯誤:
[c-sharp] view plaincopyprint?
- error C2589: '(' : illegal token on right side of '::'
error C2589: '(' : illegal token on right side of '::'
百思不得其解,後來突然想到max和min很有可能已經被定義成了宏,於是查看包進來的標頭檔,發現蹊蹺肯定在<windows.h>中:
windows.h包括了windef.h標頭檔,在windef.h中定義有宏:
[c-sharp] view plaincopyprint?
- #ifndef NOMINMAX
-
- #ifndef max
- #define max(a,b) (((a) > (b)) ? (a) : (b))
- #endif
-
- #ifndef min
- #define min(a,b) (((a) < (b)) ? (a) : (b))
- #endif
-
- #endif /* NOMINMAX */
#ifndef NOMINMAX#ifndef max#define max(a,b) (((a) > (b)) ? (a) : (b))#endif#ifndef min#define min(a,b) (((a) < (b)) ? (a) : (b))#endif#endif /* NOMINMAX */
所以這裡的max和min的宏定義就與標準模板庫中的numeric_limits<*>::max/min的定義發生了衝突,加入#define NOMINMAX問題就解決了。
(注意宏的範圍都是全域(scope-less evil)的)
進一步去google了一下關於類似的max/min宏的定義還發生在哪些常用的標頭檔中。
這裡指出,max/min的宏定義還出現在了stdlib.h和minmax.h標頭檔中。
在stdlib.h中:
[c-sharp] view plaincopyprint?
- #if !__STDC__
-
- #ifndef _POSIX_
-
- /* Non-ANSI names for compatibility */
-
- #ifndef __cplusplus
- #define max(a,b) (((a) > (b)) ? (a) : (b))
- #define min(a,b) (((a) < (b)) ? (a) : (b))
- #endif
-
- ...
#if !__STDC__#ifndef _POSIX_/* Non-ANSI names for compatibility */#ifndef __cplusplus#define max(a,b) (((a) > (b)) ? (a) : (b))#define min(a,b) (((a) < (b)) ? (a) : (b))#endif...
一般ANSI C中使用__max和__min宏,max和min只是在非標準C中才會定義,所以一般使用標準C時,包括了stdlib.h標頭檔不會發生和max/min宏的衝突。
而minmax.h標頭檔一般只是在你想使用max/min宏時才會被包括進來。
並且,在網上還發現了此問題的另外一個解決方式:
[c-sharp] view plaincopyprint?
- (std::min)(x, y);
- (std::max)(x, y);
- (std::numeric_limits<T>::min)();
- (std::numeric_limits<T>::max)();
(std::min)(x, y);(std::max)(x, y);(std::numeric_limits<T>::min)();(std::numeric_limits<T>::max)();
這樣把函數名用括弧括起來了,max/min不再被當作帶參數的宏去替換了,因此能夠避免衝突。
當使用者自己定義的類型的成員函數與全域的宏定義發生衝突時,都可以採用這種解決方案。
[c-sharp] view plaincopyprint?
- template <typename T, int Size>
- struct Series
- {
- T min() { return *(std::min_element(s, s + Size); }
- T& operator[](int index) { return s[index]; }
- private:
- T s[Size];
- };
-
- Series<int, 3> s;
- s[0] = 2;
- s[1] = 3;
- s[2] = 1;
-
- int m = (s.min)(); // long way, but here is the trick
template <typename T, int Size>struct Series{ T min() { return *(std::min_element(s, s + Size); } T& operator[](int index) { return s[index]; }private: T s[Size];};Series<int, 3> s;s[0] = 2;s[1] = 3;s[2] = 1;int m = (s.min)(); // long way, but here is the trick
只是,這種方式可能會面臨一些負面影響:
這種方式下不能使用ADL(Argument Depended Name Lookup)了,所以成員函數前必須加上類名或者名字空間網域名稱,也就是必須是fully qualified。
轉至 http://blog.csdn.net/rnamatrix/article/details/5765462
今天在使用limits中的numeric_limits類模板函數max和min時,編譯出現了一個錯誤:
[c-sharp] view plaincopyprint?
- error C2589: '(' : illegal token on right side of '::'
error C2589: '(' : illegal token on right side of '::'
百思不得其解,後來突然想到max和min很有可能已經被定義成了宏,於是查看包進來的標頭檔,發現蹊蹺肯定在<windows.h>中:
windows.h包括了windef.h標頭檔,在windef.h中定義有宏:
[c-sharp] view plaincopyprint?
- #ifndef NOMINMAX
-
- #ifndef max
- #define max(a,b) (((a) > (b)) ? (a) : (b))
- #endif
-
- #ifndef min
- #define min(a,b) (((a) < (b)) ? (a) : (b))
- #endif
-
- #endif /* NOMINMAX */
#ifndef NOMINMAX#ifndef max#define max(a,b) (((a) > (b)) ? (a) : (b))#endif#ifndef min#define min(a,b) (((a) < (b)) ? (a) : (b))#endif#endif /* NOMINMAX */
所以這裡的max和min的宏定義就與標準模板庫中的numeric_limits<*>::max/min的定義發生了衝突,加入#define NOMINMAX問題就解決了。
(注意宏的範圍都是全域(scope-less evil)的)
進一步去google了一下關於類似的max/min宏的定義還發生在哪些常用的標頭檔中。
這裡指出,max/min的宏定義還出現在了stdlib.h和minmax.h標頭檔中。
在stdlib.h中:
[c-sharp] view plaincopyprint?
- #if !__STDC__
-
- #ifndef _POSIX_
-
- /* Non-ANSI names for compatibility */
-
- #ifndef __cplusplus
- #define max(a,b) (((a) > (b)) ? (a) : (b))
- #define min(a,b) (((a) < (b)) ? (a) : (b))
- #endif
-
- ...
#if !__STDC__#ifndef _POSIX_/* Non-ANSI names for compatibility */#ifndef __cplusplus#define max(a,b) (((a) > (b)) ? (a) : (b))#define min(a,b) (((a) < (b)) ? (a) : (b))#endif...
一般ANSI C中使用__max和__min宏,max和min只是在非標準C中才會定義,所以一般使用標準C時,包括了stdlib.h標頭檔不會發生和max/min宏的衝突。
而minmax.h標頭檔一般只是在你想使用max/min宏時才會被包括進來。
並且,在網上還發現了此問題的另外一個解決方式:
[c-sharp] view plaincopyprint?
- (std::min)(x, y);
- (std::max)(x, y);
- (std::numeric_limits<T>::min)();
- (std::numeric_limits<T>::max)();
(std::min)(x, y);(std::max)(x, y);(std::numeric_limits<T>::min)();(std::numeric_limits<T>::max)();
這樣把函數名用括弧括起來了,max/min不再被當作帶參數的宏去替換了,因此能夠避免衝突。
當使用者自己定義的類型的成員函數與全域的宏定義發生衝突時,都可以採用這種解決方案。
[c-sharp] view plaincopyprint?
- template <typename T, int Size>
- struct Series
- {
- T min() { return *(std::min_element(s, s + Size); }
- T& operator[](int index) { return s[index]; }
- private:
- T s[Size];
- };
-
- Series<int, 3> s;
- s[0] = 2;
- s[1] = 3;
- s[2] = 1;
-
- int m = (s.min)(); // long way, but here is the trick
template <typename T, int Size>struct Series{ T min() { return *(std::min_element(s, s + Size); } T& operator[](int index) { return s[index]; }private: T s[Size];};Series<int, 3> s;s[0] = 2;s[1] = 3;s[2] = 1;int m = (s.min)(); // long way, but here is the trick
只是,這種方式可能會面臨一些負面影響:
這種方式下不能使用ADL(Argument Depended Name Lookup)了,所以成員函數前必須加上類名或者名字空間網域名稱,也就是必須是fully qualified。