macos 为什么在 Mac OS X 上使用 size_t 时 uint32_t 和 uint64_t 之间存在歧义?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11603818/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 09:21:44  来源:igfitidea点击:

Why is there ambiguity between uint32_t and uint64_t when using size_t on Mac OS X?

c++macosgccambiguous

提问by maxschlepzig

Consider following example code:

考虑以下示例代码:

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

This fails on Mac OSX with:

这在 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

Why? Because 'size_t' should be unsigned and either 32 bit or 64 bit wide. Where is the ambiguity then?

为什么?因为 'size_t' 应该是无符号的并且是 32 位或 64 位宽。那么歧义在哪里呢?

Trying the same with 'unsigned long x' instead of 'size_t x' results in an analogous ambiguity error message.

尝试使用 'unsigned long x' 而不是 'size_t x' 会导致类似的歧义错误消息。

On Linux/Solaris systems, testing with different GCC versions, different architectures etc. there is no ambiguity reported (and the right overload is used on each architecture).

在 Linux/Solaris 系统上,使用不同的 GCC 版本、不同的体系结构等进行测试,没有歧义报告(并且在每个体系结构上使用了正确的重载)。

Is this a Mac OS X bug or a feature?

这是 Mac OS X 的错误还是功能?

采纳答案by trojanfoe

Under Mac OS, those types are defined as:

在 Mac OS 下,这些类型定义为:

typedef unsigned int         uint32_t;
typedef unsigned long long   uint64_t;

Where as size_tis defined as __SIZE_TYPE__:

其中 assize_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

So if you change your code to:

因此,如果您将代码更改为:

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

And run it, you will get:

运行它,你会得到:

$ g++ -o test test.cpp
$ ./test
8
8
4
8
3

回答by Quuxplusone

If you really want to, you could implement your desired semantics like this:

如果你真的想要,你可以像这样实现你想要的语义:

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

Not saying this is a good idea; just saying you could do it.

不是说这是个好主意;只是说你可以做到。

There may be a good standard-C++ way to ask the compiler "are these two types the same, you know what I mean, don't act dumb with me", but if there is, I don't know it.

可能有一个很好的标准 C++ 方式来询问编译器“这两种类型是否相同,你知道我的意思,不要跟我装傻”,但如果有,我不知道。



2020 UPDATE: You could have done it more idiomatically without macros. C++14 gave us the shorthand enable_if_tand C++17 gave us is_integral_v:

2020 年更新:如果没有宏,您可以更惯用地完成它。C++14 给了我们速记enable_if_t,C++17 给了我们is_integral_v

template<int Bits, class T>
constexpr bool is_uint_v = 
    sizeof(T)==(Bits/8) && std::is_integral_v<T> && !std::is_signed_v<T>;

template<class T> auto f(T) -> std::enable_if_t<is_uint_v<32, T>, int>
    { return 1; }

template<class T> auto f(T) -> std::enable_if_t<is_uint_v<64, T>, int>
    { return 2; }

And then in C++20 we have the even-shorter-shorthand requires:

然后在 C++20 中,我们有更短的速记requires

template<int Bits, class T>
constexpr bool is_uint_v =
    sizeof(T)==(Bits/8) && std::is_integral_v<T> && !std::is_signed_v<T>;

template<class T> int f(T) requires is_uint_v<32, T> { return 1; }
template<class T> int f(T) requires is_uint_v<64, T> { return 2; }

and even-shorter-shorter-shorthand "abbreviated function templates" (although this is getting frankly obfuscated and I would not recommend it in real life):

甚至更短更短的速记“缩写函数模板”(尽管坦率地说这是混淆了,我不会在现实生活中推荐它):

template<class T, int Bits>
concept uint =
    sizeof(T)==(Bits/8) && std::is_integral_v<T> && !std::is_signed_v<T>;

int f(uint<32> auto) { return 1; }  // still a template
int f(uint<64> auto) { return 2; }  // still a template