基本类型的 static_cast<T> 与 T(n)

Posted

技术标签:

【中文标题】基本类型的 static_cast<T> 与 T(n)【英文标题】:static_cast<T> vs T(n) for fundamental types 【发布时间】:2017-01-19 18:33:15 【问题描述】:

假设我有一个这样的宏:

#define IS_SIGNED_B(T) (static_cast<T>(-1)<0)

这样写可以吗

#define IS_SIGNED_B(T) (T(-1)<0)

知道 T 是(应该)始终是基本类型。以及其他各种我需要某个值才能显式地属于某种类型的情况。

我知道这可能会导致以下情况出现问题:

signed char(0);

但知道我有基本类型 typedef'ed 为:

typedef signed char Int8;
Int8(0);

除此之外还有其他问题吗?基本类型的构造函数可以被认为与静态转换相同吗?

编辑:我知道std::numeric_limitsstd::is_signed 的存在。这只是一个例子。不是实际情况。我很抱歉没有提到这一点。

【问题讨论】:

就我个人而言,我会避免这一切以及我们std::numeric_limits::is_signed std::is_signed 存在时,为什么你需要一个宏? 您似乎认为T(-1)T 调用T == int 的构造函数,但是,这只是c 样式转换的替代语法,它可能被实现为static_cast,所以应该没有区别。 @Borgleader 不错。我不知道他们为 制作了免费版本。直到 :) 我知道 std::numeric_limits 和/或 type_traits 的存在。这只是一个例子。目前我想不出更好的。 【参考方案1】:

可以认为基本类型的构造函数与静态转换相同吗?

基本类型没有构造函数。 Int8(0)(Int8)0 的显式类型转换和替代语法。这被称为 C 风格演员表。另一种语法称为函数转换表达式。

对于基本的整数类型,C 风格的转换等价于 static_cast。但一般不等价。如果没有可用的 static_cast,那么它将执行 reinterpret_cast(或 const_cast,或 const_cast 和其他类型之一的组合)。

除此之外还有其他问题吗?

我不太明白您提出了什么问题,但是是的,显式类型转换确实存在大问题。主要问题是程序员并不完美,你不能假设T is (should) always be a fundamental type 总是成立。您希望编译器捕获此类错误。 C 风格的转换将隐藏您或您的同事可能犯的一些错误,并用未定义的行为替换错误消息。

也许在您的宏的上下文中,未定义行为的危险很小,但正如您所说,这只是一个示例。一个好的经验法则:更喜欢使用您想要的确切类型的 *_cast,而不是让 C 风格的转换选择可能不是您想要的类型之一。

【讨论】:

谢谢。这都是我想知道的。是否可以将其视为静态转换或 C 样式转换。这一直困扰着我一段时间,我想我忘记了我需要清楚了解这一点的情况。对于没有正确提出问题,我深表歉意。【参考方案2】:

您应该做的第一件事是停止不必要地使用 C 预处理器。

只需使用std::is_signed。

如果做不到这一点,类似于:

template<class T>
constexpr
std::integral_constant<bool,
  (static_cast<T>(-1)<0)
> is_signed_b()  return ; 

这是您宏的工业级版本。

它返回一个空类,该类具有 constexpr 转换为布尔值,其值是您想要的结果。它可以在编译时进行评估(事实上,它很难不被评估)。


但是你的宏有什么问题?

首先,你的宏应该是:

#define IS_SIGNED_B(...) (static_cast<__VA_ARGS__>(-1)<0)

因为

IS_SIGNED_B( std::tuple_element_t<some_tuple, Is> )...

不必要地中断你的实现。

C 预处理器不理解 C++。它不明白,s 不再包含在() 中。

如前所述,如果 T 是双字类型,您的代码将中断。

另一个问题是,如果你给它一个不是整数类型的类型,奇怪的事情就会发生。 C 风格的强制转换很强大,并且适用于指针类型。因此,您将在左侧获得-1 的指针类型值。在右侧,您将获得0,它隐式转换为任何指针类型的空值。然后进行比较。本段包含各种未定义的行为。

【讨论】:

以上是关于基本类型的 static_cast<T> 与 T(n)的主要内容,如果未能解决你的问题,请参考以下文章

使 .natvis 将 SmartPointer<T> 显示为 static_cast<T*>(void*)

C++类型转换基本语法

C++中“强制转换”的四大天王

C++:类型转换

static_cast<T>(-1) 是在没有 numeric_limits 的情况下生成全一位数据的正确方法吗?

二维数组初始化vector, 以及类型转换问题