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_limits
和 std::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
,它隐式转换为任何指针类型的空值。然后比较事物。本段包含各种未定义的行为。
假设我有一个这样的宏:
#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_limits
和 std::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
,它隐式转换为任何指针类型的空值。然后比较事物。本段包含各种未定义的行为。