Search code examples
c++c++11constructorprimitivestatic-cast

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


Let's assume I have a macro like this:

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

Would it be alright to write it as

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

Knowing that T is (should) always be a fundamental type. And various other cases where I need a certain value to be explicitly of a certain type.

I know this can cause issues for situations like:

signed char(0);

But knowing that I have fundamental types typedef'ed as:

typedef signed char Int8;
Int8(0);

Are there any other issues other than this? Can the constructor of a fundamental type be considered identical to a static cast?

EDIT: I know about the existence of std::numeric_limits and std::is_signed. This was just an example. Not the actual case. My apologies for not mentioning that.


Solution

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

    Fundamental types have no constructors. Int8(0) is an explicit type conversion and alternative syntax for (Int8)0. This is known as C-style cast. The alternative syntax is called a functional cast expression.

    For fundamental integral types, C-style cast is equivalent to a static_cast. But it is not equivalent in general. If there is no static_cast available, then it will perform reinterpret_cast (or const_cast, or the combination of const_cast, and one of the other casts).

    Are there any other issues other than this?

    I don't quite understand what issue or issues you have presented, but yes explicit type conversions do have big issues. The major issue is that programmers aren't perfect, and you cannot assume that T is (should) always be a fundamental type always holds. You want the compiler to catch such mistakes. A C-style cast will hide some of the mistakes that you or your colleagues might make, and replace error messages with undefined behaviour.

    Perhaps in the context of your macro, there is little danger of undefined behaviour, but as you said, that was just an example. A good rule of thumb: Prefer using the exact type of *_cast that you intend, instead of letting C-style cast pick one of the casts that might not be what you intended.