我们假设我有一个像这样的宏:
#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
的存在。这只是一个例子。不是实际情况。我很抱歉没有提到这一点。
答案 0 :(得分:4)
基本类型的构造函数可以被认为与静态转换相同吗?
基本类型没有构造函数。 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风格的角色选择其中一个可能不是您想要的角色。
答案 1 :(得分:2)
你应该做的第一件事是不必要地停止使用C预处理器。
只需使用std::is_signed。
失败,例如:
template<class T>
constexpr
std::integral_constant<bool,
(static_cast<T>(-1)<0)
> is_signed_b() { return {}; }
这是宏的工业强度版本。
它返回一个空类,它有一个constexpr转换为bool,其值是您想要的结果。它可以在编译时进行评估(事实上,它很难不被编译)。
但你的宏有什么问题?
首先,你的宏应该是:
#define IS_SIGNED_B(...) (static_cast<__VA_ARGS__>(-1)<0)
,因为
IS_SIGNED_B( std::tuple_element_t<some_tuple, Is> )...
不必要地执行您的实施。
C预处理器不理解C ++。它不理解,
或()
中不再包含{}
。
如上所述,如果T
是双字类型,则代码会中断。
另一个问题是,如果你提供一个不是整数类型的类型,就会发生奇怪的事情。 C风格的强制转换很强大,适用于指针类型。因此,您将在左侧获得指针类型值-1
。在右侧,您将获得0
,它隐式转换为任何指针类型的空值。然后比较事情。本段包含各种未定义的行为。