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
Discussions

static_cast - C++ Forum
I'm having some trouble understanding when you can and cannot cast between pointers. For example · fails because line 2 is an "invalid type conversion". More on cplusplus.com
🌐 cplusplus.com
August 18, 2024
c++ - Why can't I static_cast between char * and unsigned char *? - Stack Overflow
Apparently the compiler considers them to be unrelated types and hence reinterpret_cast is required. Why is this the rule? More on stackoverflow.com
🌐 stackoverflow.com
error: invalid static_cast from type ‘const void*’ to type ‘void (*)()’
There was an error while loading. Please reload this page · Calling std::cout << fun_void_void works fine, but tfm::format( "1. %s", fun_void_void ) (either %s or %p) results in: More on github.com
🌐 github.com
1
October 20, 2019
c++ - invalid cast from char* to int* - Stack Overflow
I am trying to use a buffer of char on the stack as storage for some other type of data. As test I started with the most basic int but casting pointer of chars to pointer of integer doesn't compil... More on stackoverflow.com
🌐 stackoverflow.com
🌐
Cplusplus
cplusplus.com › forum › beginner › 163866
static_cast - C++ Forum
August 18, 2024 - 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.
🌐
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.
🌐
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
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.

🌐
GitHub
github.com › c42f › tinyformat › issues › 72
error: invalid static_cast from type ‘const void*’ to type ‘void (*)()’ · Issue #72 · c42f/tinyformat
October 20, 2019 - (Args)> tinyformat::makeFormatList(const Args& ...) [with Args = {void()}]’ tinyformat.h:1089:37: required from ‘void tinyformat::format(std::ostream&, const char*, const Args& ...) [with Args = {void()}; std::ostream = std::basic_ostream<char>]’ tinyformat.h:1098:11: required from ‘std::string tinyformat::format(const char*, const Args& ...) [with Args = {void()}; std::string = std::basic_string<char>]’ test_debugger4.cpp:9:54: required from here tinyformat.h:574:45: error: invalid static_cast from type ‘const void*’ to type ‘void (*)()’ return convertToInt<T>::invoke(*static_cast<const T*>(value)); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
Author   evandrocoan
Find elsewhere
🌐
Rip Tutorial
riptutorial.com › invalid base-to-derived static cast
C++ Tutorial => Invalid base-to-derived static cast
March 28, 2016 - 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.
🌐
Narkive
comp.lang.cpp.moderated.narkive.com › hXILkq2G › casting-to-function-pointer
casting to function pointer - comp.lang.c++.moderated - narkive
February 12, 2019 - Now, what really struck me is when I ported this to GCC 3.3: I had a static_cast<fn*>(raw) for the conversion, but the compiler rejected invalid static_cast from type `void*' to type `void (*)()' The reason why this struck me was that I was under the impression that static_cast was closest to a C-Style cast(with the only difference that it works const/volatile-correct).
🌐
CodeBurst
codeburst.io › understanding-c-casts-ef1f36e54240
Understanding C++ Casts. C++, being a strongly typed language… | by Aniket Bhattacharyea | codeburst
August 27, 2013 - But every Mammal may not be a Human. So implicit conversion from Mammal * to Human * is not allowed. That’s where static_cast comes in. If we omit the static cast, we’ll get an error something along the line of · invalid conversion from ‘Mammal*’ to ‘Human*’
🌐
Narkive
wx-users.wxwidgets.narkive.com › Fc4BehCS › problems-with-event-table-throwing-invalid-static-cast
problems with EVENT_TABLE throwing invalid static_cast
October 30, 2024 - EVT_BUTTON(CV_URI_BTN_ID , CertificateViewer::onUpdateCrl) <---------this is line 57 END_EVENT_TABLE(); ===== CertificateViewer.cpp:57: error: invalid static_cast from type `bool (CertificateViewer::*)(wxCommandEvent&)' to type `void (wxEvtHandler::*)(wxCommandEvent&)' Your CertificateViewer::onUpdateCrl method needs to have a return type of void, not bool.
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

🌐
Microsoft Learn
learn.microsoft.com › en-us › cpp › cpp › type-conversions-and-type-safety-modern-cpp
Type conversions and type safety | Microsoft Learn
April 17, 2019 - static_cast, for casts that are checked at compile time only. static_cast returns an error if the compiler detects that you are trying to cast between types that are completely incompatible.
🌐
Oracle
docs.oracle.com › cd › E19422-01 › 819-3690 › Cast.html
C H A P T E R 9 - Cast Operations
March 30, 2025 - A static_cast cannot be used to cast down from a virtual base class. A pointer (or reference) to a class can actually point (refer) to any class derived from that class. Occasionally, it may be desirable to obtain a pointer to the fully derived class, or to some other subobject of the complete ...
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!

🌐
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
August 17, 2023 - 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 ·
🌐
GeeksforGeeks
geeksforgeeks.org › static_cast-in-c-type-casting-operators
static_cast in C++ | Type Casting operators - GeeksforGeeks
July 22, 2017 - This means that even if you think you can some how typecast a particular object int another but its illegal, static_cast will not allow you to do this. Lets take another example of converting object to and from a class.