Почему существует двусмысленность между uint32 t и uint64 t при использовании размера t в Mac OS X?
рассмотрим следующий пример кода:
#include <iostream>
#include <inttypes.h>
using namespace std;
int f(uint32_t i)
{
return 1;
}
int f(uint64_t i)
{
return 2;
}
int main ()
{
cout << sizeof(long unsigned) << 'n';
cout << sizeof(size_t) << 'n';
cout << sizeof(uint32_t) << 'n';
cout << sizeof(uint64_t) << 'n';
//long unsigned x = 3;
size_t x = 3;
cout << f(x) << 'n';
return 0;
}
это не удается на Mac OSX с:
$ g++ --version
i686-apple-darwin10-g++-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5664)
$ make test
g++ test.cc -o test
test.cc: In function 'int main()':
test.cc:23: error: call of overloaded 'f(size_t&)' is ambiguous
test.cc:6: note: candidates are: int f(uint32_t)
test.cc:10: note: int f(uint64_t)
make: *** [test] Error 1
почему? Потому что 'size_t' должен быть без знака и 32 бит или 64 бит в ширину. Где же тогда двусмысленность?
попытка сделать то же самое с "unsigned long x "вместо" size_t x " приводит к аналогичное сообщение об ошибке неопределенности.
в системах Linux / Solaris, тестирование с различными версиями GCC, различными архитектурами и т. д. нет никакой двусмысленности (и правая перегрузка используется для каждой архитектуры).
это ошибка Mac OS X или функция?
2 ответов
в Mac OS эти типы определяются как:
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
где size_t
определяется как __SIZE_TYPE__
:
#if defined(__GNUC__) && defined(__SIZE_TYPE__)
typedef __SIZE_TYPE__ __darwin_size_t; /* sizeof() */
#else
typedef unsigned long __darwin_size_t; /* sizeof() */
#endif
Итак, если вы измените свой код на:
#include <iostream>
#include <inttypes.h>
using namespace std;
int f(uint32_t i)
{
return 1;
}
int f(uint64_t i)
{
return 2;
}
int f (unsigned long i)
{
return 3;
}
int main ()
{
cout << sizeof(unsigned long) << '\n';
cout << sizeof(size_t) << '\n';
cout << sizeof(uint32_t) << '\n';
cout << sizeof(uint64_t) << '\n';
//long unsigned x = 3;
size_t x = 3;
cout << f(x) << '\n';
return 0;
}
и запустите его, вы получите:
$ g++ -o test test.cpp
$ ./test
8
8
4
8
3
Если вы действительно хотите, вы можете реализовать желаемую семантику следующим образом:
#define IS_UINT(bits, t) (sizeof(t)==(bits/8) && \
std::is_integral<t>::value && \
!std::is_signed<t>::value)
template<class T> auto f(T) -> typename std::enable_if<IS_UINT(32,T), int>::type
{
return 1;
}
template<class T> auto f(T) -> typename std::enable_if<IS_UINT(64,T), int>::type
{
return 2;
}
Не говорить, что это хорошая идея; просто сказать, что вы могли бы это сделать.
может быть хороший стандартный-C++ способ спросить компилятор "эти два типа одинаковы, вы знаете, что я имею в виду, не ведите себя глупо со мной", но если есть, я этого не знаю.