基本类型的 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_limits
和std::is_signed
的存在。这只是一个例子。不是实际情况。我很抱歉没有提到这一点。
【问题讨论】:
就我个人而言,我会避免这一切以及我们std::numeric_limits::is_signed
当std::is_signed
存在时,为什么你需要一个宏?
您似乎认为T(-1)
为T
调用T == int
的构造函数,但是,这只是c 样式转换的替代语法,它可能被实现为static_cast
,所以应该没有区别。
@Borgleader 不错。我不知道他们为 可以认为基本类型的构造函数与静态转换相同吗?
基本类型没有构造函数。 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*)