Static cast will also fail if the compiler doesn't know (or is pretending not to know) about the relationship between the types. If your inheritance isn't declared public between the two, the compiler will consider them as unrelated types and give you the same cryptic warning.

This just bit me, so thought I'd share.

Answer from Dragos on Stack Overflow
Top answer
1 of 2
7
long *plDog = static_cast<long*>(piDog); // invalid type conversion

Why is my static_cast of a pointer failing?

Because it is ill-formed. None of the rules of static_cast apply to the cast that you're attempting. It is an invalid conversion, as you mention in the comments.

A pointer to one object type may not be static casted to a pointer to another object type unless they are pointers to related classes, or when casting to/from pointer to void.

This reference suggests it should be OK: https://en.cppreference.com/w/cpp/language/static_cast

That reference suggests that the conversion you attempt is not OK.

long* plDog = (long*)(piDog); // this is OK too... very weird!!

This is a well-formed conversion. It's not "weird".

There are many conversions that explicit conversions (also called "cast notation" or "C-style cast") allow, and static casts do not allow. This is because static casts have (at least a semblance of) type safety while explicit conversions essentially ask the compiler to pretend that the type system doesn't exist.

Note that indirecting through plDog and accessing the object would result in undefined behaviour. As you can see, it was a good thing that you got the error.

and we aren't allowed to use this one in our coding standards

This is a good limitation to have. This will make it bit harder for your team to write bugs by mistakenly circumventing the type system.

Issue with Visual Studio C++?

No, the issue is that the program is ill-formed. The compiler is correct to inform you about the bug, and is not required to compile the program.


I recommend asking yourself: Why do you want to, or think that you need to do such cast?

2 of 2
0

TL;DR: If your cast worked, the language would provide no type-safety guarantees for pointers, and is a key part of the motivation for introducing the C++ style casts instead of sticking with the old-school C cast.

In the language of the C/C++ Standard, long* and int* are not "pointer-compatible". You can't implicitly convert a long* to an int* or vice-versa, so static_cast can't do it in a single cast.

The reasoning behind that is sizeof(long) is not always equal to sizeof(int) for all platforms. They are distinct fundamental types. This is true in general of all distinct C/C++ types even if they have an identical binary layout. They are only "pointer-compatible" if in the syntax of the language you declare the types to be related via implicit conversion.

You can use static_cast when converting from a void* to any pointer to an object type or vice-versa.

Therefore you can do this in two ways:

  • reinterpret_cast<long*>(piDog);

-or-

  • static_cast<long*>(static_cast<void*>(piDog));

Stylistically, the use of the reinterpret_cast is a lot clearer. In either case, the validity of the cast is architecture dependent and assumes sizeof(int) == sizeof(long) as well as having the same memory layout.

IOW This is safe for Windows x86 and x64 native, but may not hold for other platforms or CPUs. This is one of the reasons Windows x64 choose to use the LLP64 data model as explained in this blog post.

See cppreference for static_cast and reinterpret_cast

Top answer
1 of 3
48

They are completely different types see standard:

3.9.1 Fundamental types [basic.fundamental]

1 Objects declared as characters char) shall be large enough to store any member of the implementation's basic character set. If a character from this set is stored in a character object, the integral value of that character object is equal to the value of the single character literal form of that character. It is implementation-defined whether a char object can hold negative values. Characters can be explicitly declared unsigned or
signed. Plain char, signed char, and unsigned char are three distinct types. A char, a signed char, and an unsigned char occupy the same amount of storage and have the same alignment requirements (basic.types); that is, they have the same object representation. For character types, all bits of the object
representation participate in the value representation. For unsigned character types, all possible bit patterns of the value representation represent numbers. These requirements do not hold for other types. In any particular implementation, a plain char object can take on either the same values as a signed char or an unsigned char; which one is implementation-defined.

So analogous to this is also why the following fails:

unsigned int* a = new unsigned int(10);
int* b = static_cast<int*>(a); // error different types

a and b are completely different types, really what you are questioning is why is static_cast so restrictive when it can perform the following without problem

unsigned int a = unsigned int(10);
int b = static_cast<int>(a); // OK but may result in loss of precision

and why can it not deduce that the target types are the same bit-field width and can be represented? It can do this for scalar types but for pointers, unless the target is derived from the source and you wish to perform a downcast then casting between pointers is not going to work.

Bjarne Stroustrop states why static_cast's are useful in this link: http://www.stroustrup.com/bs_faq2.html#static-cast but in abbreviated form it is for the user to state clearly what their intentions are and to give the compiler the opportunity to check that what you are intending can be achieved, since static_cast does not support casting between different pointer types then the compiler can catch this error to alert the user and if they really want to do this conversion they then should use reinterpret_cast.

2 of 3
11

you're trying to convert unrelated pointers with a static_cast. That's not what static_cast is for. Here you can see: Type Casting.

With static_cast you can convert numerical data (e.g. char to unsigned char should work) or pointer to related classes (related by some inheritance). This is both not the case. You want to convert one unrelated pointer to another so you have to use reinterpret_cast.

Basically what you are trying to do is for the compiler the same as trying to convert a char * to a void *.


Ok, here some additional thoughts why allowing this is fundamentally wrong. static_cast can be used to convert numerical types into each other. So it is perfectly legal to write the following:

char x = 5;
unsigned char y = static_cast<unsigned char>(x);

what is also possible:

double d = 1.2;
int i = static_cast<int>(d);

If you look at this code in assembler you'll see that the second cast is not a mere re-interpretation of the bit pattern of d but instead some assembler instructions for conversions are inserted here.

Now if we extend this behavior to arrays, the case where simply a different way of interpreting the bit pattern is sufficient, it might work. But what about casting arrays of doubles to arrays of ints? That's where you either have to declare that you simple want a re-interpretation of the bit patterns - there's a mechanism for that called reinterpret_cast, or you must do some extra work. As you can see simple extending the static_cast for pointer / arrays is not sufficient since it needs to behave similar to static_casting single values of the types. This sometimes needs extra code and it is not clearly definable how this should be done for arrays. In your case - stopping at \0 - because it's the convention? This is not sufficient for non-string cases (number). What will happen if the size of the data-type changes (e.g. int vs. double on x86-32bit)?

The behavior you want can't be properly defined for all use-cases that's why it's not in the C++ standard. Otherwise you would have to remember things like: "i can cast this type to the other as long as they are of type integer, have the same width and ...". This way it's totally clear - either they are related CLASSES - then you can cast the pointers, or they are numerical types - then you can cast the values.

Top answer
1 of 3
3

If-statements don't make compile-time decisions; the compiler will always check both branches.

You need to create an overloaded write() function, where the default version streams to cout, and which you can overload for specific types (such as char).

2 of 3
2

The problem:

Like your compiler said:

error: invalid static_cast from type ‘std::basic_string<char, std::char_traits<char>,  
std::allocator<char> >’ to type ‘int16_t’

I suppose your calling your log function like this:

log("my % thing %....", /*my std::string*/ stringToto, 5,/*....*/);

And there is the problem!

When the compiler see you want to static_cast a std::string to a int16_t it generate an error!

What you've done wrong

This part:

    if ( std::is_same<T, uint8_t>::value || std::is_same<T, int8_t>::value )
    {
        int16_t x = value1;
        int16_t x = static_cast<int16_t>(value1);
        std::cout << x;
    }
    else
    {
       std::cout << value1;
    }

Why? In fact, even if your condition (std::is_same<T, uint8_t>::value || std::is_same<T, int8_t>::value) is false, your compiler will interpret your static_cast

What should you do

Use a function that get an argument (whatever is its type) and generate an std::string, like this:

template<typename T>
std::string
my_to_string(T) { return ("what is this type?"); }

template<>
std::string
my_to_string(std::string s) { return (s); }

template<>
std::string
my_to_string(int integer) { return (std::to_string(integer)); }

and then call it in your log function like this: std::cout << my_to_string(value1);

Good Luck improving your work!

🌐
Rip Tutorial
riptutorial.com › invalid base-to-derived static cast
C++ Tutorial => Invalid base-to-derived static cast
If static_cast is used to convert a pointer (resp. reference) to base class to a pointer (resp. reference) to derived class, but the operand does not point (resp. refer) to an object of the derived class type, the behavior is undefined.
Find elsewhere
🌐
Cppreference
en.cppreference.com › w › cpp › language › static_cast.html
static_cast conversion - cppreference.com
Base-to-derived conversions (downcasts) using static_cast make no runtime checks to ensure that the dynamic type of the pointed/referred object is Derived, and may only be used safely if this precondition is guaranteed by other means, such as when implementing static polymorphism.
🌐
Stack Overflow
stackoverflow.com › questions › tagged › static-cast
Newest 'static-cast' Questions - Stack Overflow
In this function I static_cast this to a const pointer to a const B and ... ... I have two integers, m and k. The product of m and k might overflow an int datatype, so I used long long int data type but I was still getting runtime error: signed integer overflow: 89945 * 32127 ...
🌐
Learn C++
learncpp.com › cpp-tutorial › explicit-type-conversion-casting-and-static-cast
10.6 — Explicit type conversion (casting) and static_cast – Learn C++
March 4, 2025 - First, static_cast provides compile-time type checking. If we try to convert a value to a type and the compiler doesn’t know how to perform that conversion, we will get a compilation error. // a C-style string literal can't be converted to an int, so the following is an invalid conversion int x { static_cast<int>("Hello") }; // invalid: will produce compilation error
🌐
Stack Overflow
stackoverflow.com › questions › 71684373 › error-invalid-static-cast-from-type-m256i-aka-vector4-long-long-int
c++ - error: invalid static_cast from type ‘__m256i’ {aka ‘__vector(4) long long int’} to type ‘void*’ - Stack Overflow
March 30, 2022 - But anyway, __m256i is not a value type that it makes sense to cast to a pointer value. Adding a scalar int64_t with + does compile in GNU C++, as equivalent to _mm256_add_epi64(value, _mm256_set1_epi64(i)); gcc.gnu.org/onlinedocs/gcc/Vector-Extensions.html ... Join us for our first community-wide AMA (Ask Me Anything) with Stack...
🌐
Stack Overflow
stackoverflow.com › questions › 79417324 › what-is-the-correct-type-of-cast-to-use-for-non-typesafe-pointer-conversions-for
c++ - What is the correct type of cast to use for non-typesafe pointer conversions for binary data reinterpret operations? - Stack Overflow
std::vector<uint64_t> buffer; // call `recv` const auto p_length = &(buffer[some_offset]); const auto p_length_as_uint64_t = static_cast<const uint64_t* const>(p_length); const uint64_t length = *p_length_as_uint64_t; This code does not compile. The error message is · Error: Invalid type conversion ·
🌐
Cplusplus
cplusplus.com › forum › beginner › 163866
static_cast - C++ Forum
May 1, 2015 - Removing that type system and using a generic void pointer doesn't change what you're pointing to, it only makes it so you no longer know what you're pointing to -- and therefore makes your code more error prone. Of course there are legitimate times where you'd want to do this, but you generally don't want to. That said... const void* head = static_cast<void*>(new int[10]); You are actually doing 2 casts here: 1) int* to void* (explicit with your static_cast) 2) void* to const void* (implicit with your assignment) Both of these casts are legal.