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

static_cast<T> vs T(n) for fundamental types

假设我有一个这样的宏:

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

写成

可以吗
#define IS_SIGNED_B(T) (T(-1)<0)

知道 T 是(应该)始终是基本类型。以及其他各种情况,在这些情况下,我需要某个值明确属于某种类型。

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

signed char(0);

但知道我将基本类型定义为:

typedef signed char Int8;
Int8(0);

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

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

Can the constructor of a fundamental type be considered identical to a static cast?

基本类型没有构造函数。 Int8(0)(Int8)0 的显式类型转换和替代语法。这称为 C-style 转换。替代语法称为功能转换表达式。

对于基本整数类型,C-style 转换等同于 static_cast。但一般来说并不等价。如果没有 static_cast 可用,那么它将执行 reinterpret_cast(或 const_cast,或 const_cast 的组合,以及其他转换之一)。

Are there any other issues other than this?

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

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

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

只需使用std::is_signed.

否则,类似:

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

这是您的宏的工业强度版本。

它 returns 一个空的 class 它有一个 constexpr conversion-to-bool 其值是你想要的结果。它可以在编译时求值(事实上,很难不被求值)。


但是你的宏有什么问题?

首先,您的宏应为:

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

因为

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

您的实施不必要地中断。

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

如前所述,如果 T 是 two-word 类型,您的代码就会中断。

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