gpt4 book ai didi

c++ - C++ 中的 long long int 与 long int 与 int64_t

转载 作者:太空宇宙 更新时间:2023-11-04 12:36:18 26 4
gpt4 key购买 nike

我在使用 C++ 类型特征时遇到了一些奇怪的行为,并将我的问题缩小到这个古怪的小问题,因为我不想留下任何可能引起误解的问题,因此我将给出大量解释。

假设你有这样一个程序:

#include <iostream>
#include <cstdint>

template <typename T>
bool is_int64() { return false; }

template <>
bool is_int64<int64_t>() { return true; }

int main()
{
std::cout << "int:\t" << is_int64<int>() << std::endl;
std::cout << "int64_t:\t" << is_int64<int64_t>() << std::endl;
std::cout << "long int:\t" << is_int64<long int>() << std::endl;
std::cout << "long long int:\t" << is_int64<long long int>() << std::endl;

return 0;
}

在使用 GCC(以及 32 位和 64 位 MSVC)进行的 32 位编译中,程序的输出将是:

int:           0
int64_t: 1
long int: 0
long long int: 1

但是,由 64 位 GCC 编译生成的程序将输出:

int:           0
int64_t: 1
long int: 1
long long int: 0

这很奇怪,因为 long long int是一个带符号的 64 位整数,就所有意图和目的而言,与 long int 相同和 int64_t类型,所以逻辑上,int64_t , long intlong long int将是等效类型 - 使用这些类型时生成的程序集是相同的。一看stdint.h告诉我原因:

# if __WORDSIZE == 64
typedef long int int64_t;
# else
__extension__
typedef long long int int64_t;
# endif

在 64 位编译中,int64_tlong int , 不是 long long int (显然)。

这种情况的修复非常简单:

#if defined(__GNUC__) && (__WORDSIZE == 64)
template <>
bool is_int64<long long int>() { return true; }
#endif

但这非常骇人听闻并且无法很好地扩展(物质的实际功能,uint64_t 等)。 所以我的问题是:有没有办法告诉编译器一个long long int也是int64_t , 就像 long int是吗?


我最初的想法是,由于 C/C++ 类型定义的工作方式,这是不可能的。没有一种方法可以向编译器指定基本数据类型的类型等价性,因为这是编译器的工作(并且允许这样做可能会破坏很多事情)和typedef只走一条路。

我也不太关心在这里得到答案,因为这是一个 super 边缘案例,我不怀疑任何人都会关心当这些例子不是非常人为的时候(这是否意味着这应该是社区维基?)。


Append:我使用部分模板特化而不是更简单的示例的原因如下:

void go(int64_t) { }

int main()
{
long long int x = 2;
go(x);
return 0;
}

那个例子是否仍然可以编译,因为long long int可隐式转换为 int64_t .


Append:目前唯一的答案假设我想知道一个类型是否为 64 位。我不想误导人们认为我关心这个问题,并且可能应该提供更多的例子来说明这个问题在哪里出现。

template <typename T>
struct some_type_trait : boost::false_type { };

template <>
struct some_type_trait<int64_t> : boost::true_type { };

在这个例子中,some_type_trait<long int>将是 boost::true_type ,但是some_type_trait<long long int>不会是。虽然这在 C++ 的类型思想中有意义,但并不可取。

另一个例子是使用像 same_type 这样的限定符(这在 C++0x 概念中很常见):

template <typename T>
void same_type(T, T) { }

void foo()
{
long int x;
long long int y;
same_type(x, y);
}

该示例无法编译,因为 C++(正确地)发现类型不同。 g++ 将无法编译并出现如下错误:没有匹配的函数调用 same_type(long int&, long long int&) .

我想强调,我理解为什么会发生这种情况,但我正在寻找一种不会迫使我到处重复代码的解决方法。

最佳答案

您无需转到 64 位也能看到这样的内容。考虑常见 32 位平台上的 int32_t。它可能被 typedef 编辑为 intlong,但显然一次只能是两者之一。 intlong 当然是不同的类型。

不难看出,在 32 位系统上没有使 int == int32_t == long 变通的方法。出于同样的原因,没有办法在 64 位系统上制作 long == int64_t == long long

如果可以的话,对于重载 foo(int)foo(long)foo(long long) 的代码,可能的后果将是相当痛苦的 - 突然间他们对同一个重载有了两个定义?!

正确的解决方案是您的模板代码通常不应该依赖于精确的类型,而应该依赖于该类型的属性。对于特定情况,整个 same_type 逻辑仍然可以:

long foo(long x);
std::tr1::disable_if(same_type(int64_t, long), int64_t)::type foo(int64_t);

即,重载 foo(int64_t)foo(long) 完全相同时未定义。

[编辑]使用 C++11,我们现在有一种标准的方式来编写:

long foo(long x);
std::enable_if<!std::is_same<int64_t, long>::value, int64_t>::type foo(int64_t);

[编辑]或者 C++20

long foo(long x);
int64_t foo(int64_t) requires (!std::is_same_v<int64_t, long>);

关于c++ - C++ 中的 long long int 与 long int 与 int64_t,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56304368/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com