How are C++ casts implemented? - c++

The C++ casts static_cast, const_cast, reinterpret_cast have a template-like syntax, e.g.
long foo = 3;
int bar = static_cast<int>(foo);
I've looked in the Standard, and it says that casts are expressions, not template functions as I thought.
This left me wondering: under the hood, are these casts just templates with privileged status, or are they keywords that happen to borrow the template syntax?

are they keywords that happen to borrow the template syntax?
This. Casts are implemented differently depending on the context they are used in – in general, they cannot be implemented as functions. For instance, static_cast is sometimes only a compile-time operation, no code is emitted for it. But other times (in particular when invoking constructors, casting in a type hierarchy or converting between layout-incompatible primitive types) it requires a runtime operation.
That said, you can implement your own functions that resemble the standard cast syntax (boost::lexical_cast does that).

Related

Is it safe to reinterpret_cast from std::function<void()> * to std::function<std::monostate()> *?

Example:
std::function<std::monostate()> convert(std::function<void()> func){
return *reinterpret_cast<std::function<std::monostate()> * >(&func);
}
Are std::function<void()> and std::function<std::monostate()> considered "similar" enough for reinterpret_cast to be safe?
Edit: someone asked me to clarify what I am asking. I am not asking if the general case of foo<X> and foo<Y> are similar but whether foo<void> and foo<std::monostate> are.
No this is unsafe and leads to undefined behavior. In particular, there's no guarantee that the two layouts will be compatible. Of course, you might get away with it with some compiler and runtime combinations, but then it might break if some future release of your compiler decides to implement certain forms of control flow integrity.
The safe way to do what you want, albeit at a small cost in performance, is just to return a new lambda, as in:
std::function<std::monostate()> convert(std::function<void()> func){
return [func=std::move(func)]() -> std::monostate { func(); return {}; };
}
Are std::function<void()> and std::function<std::monostate()> considered "similar" enough for reinterpret_cast to be safe?
No. Given a template foo and distinct types X and Y, the instantiations foo<X> and foo<Y> are not similar, regardless of any perceived relationship between X and Y (as long as they are not the same type, which is why they were qualified as "distinct"). Different template instantiations are unrelated unless documented otherwise. There is no such documentation for std::function.
The rules for "similar" make allowances for digging into pointer types, but there is nothing special for templates. (Nor could there be, since a template specialization could look radically different than its base template.) Different types as template arguments yield dissimilar templated classes. No need to dig deeper into those arguments.
I am not asking if the general case of foo<X> and foo<Y> are similar but whether foo<void> and foo<std::monostate> are.
There is nothing special about void and std::monostate that would make them two names for the same type. (In fact, they cannot be the same type, as the former has zero values, while the latter has exactly one value.) So, asking about foo<void> and foo<std::monostate> is the same as asking about the general case, just with a greater possibility of seeing connections that do not exist.
Also, the question is not about foo<void> and foo<std::monostate> but about foo<void()> and foo<std::monostate()>. The types used as template arguments are function types, not object types. Function types are very particular in that two function types are the same only when all of their parameter and return types are exact matches; none of the conversions allowed when invoking a function are considered. (Not that there is a conversion from void to std::monostate.) The function types are different, so again the templates instantiated from those types are not similar.
Perhaps a more focused version of this question would have asked about function pointers instead of std::function objects.
(from a comment:) I was looking at the assembly code of std::monostate() functions and void() functions and they generate the same assembly verbatim.
Generated assembly means nothing as far as the language is concerned. At best, you have evidence that with your compiler, it seems likely that you could get away with invoking a function pointer after casting it from void (*)() to std::monostate (*)(). Not "safe" so much as "works for now". And that assumes that you use the function pointer directly instead of burying it inside a std::function (a complex adapter of types).
C++ is a strongly typed language. Different types are different even if they are treated the same at the level of assembly code. This might be more readily apparent if we switch to more familiar types. On many common systems, char is signed, making it equivalent to signed char at the assembly code level. However, this does not affect the similarity of functions. The following code is illegal, even if changing char to signed char has no effect on the assembly code generated for foo().
char foo() { return 'c'; }
int main()
{
signed char (*fun)() = foo; // <-- Error: invalid conversion
// ^^^^^^ -- because the return type is signed char, not char
}
One can downgrade this error to a warning with a reinterpret_cast. After all, it is legal to cast a function pointer to any function pointer type. However, it is not safe to invoke the function through the cast pointer (unless cast back to the original type), hence the warning. Invoking it might work very reliably on your system, but that is due to your system, not the language. When you ask about "safe", you are asking for guidance from the language specs, not merely what will probably work on your system.

Does the C++ specification say how types are chosen in the static_cast/const_cast chain to be used in a C-style cast?

This question concerns something I noticed in the C++ spec when I was trying to answer this earlier, intriguing question about C-style casts and type conversions.
The C++ spec talks about C-style casts in §5.4. It says that the cast notation will try the following casts, in this order, until one is found that is valid:
const_cast
static_cast
static_cast followed by const_cast
reinterpret_cast
reinterpret_cast followed by const_cast.
While I have a great intuitive idea of what it means to use a static_cast followed by a const_cast (for example, to convert a const Derived* to a Base* by going through a const_cast<Base*>(static_cast<const Base*>(expr))), I don't see any wording in the spec saying how, specifically, the types used in the static_cast/const_cast series are to be deduced. In the case of simple pointers it's not that hard, but as seen in the linked question the cast might succeed if an extra const is introduced in one place and removed in another.
Are there any rules governing how a compiler is supposed to determine what types to use in the casting chain? If so, where are they? If not, is this a defect in the language, or are there sufficient implicit rules to uniquely determine all the possible casts to try?
If not, is this a defect in the language, or are there sufficient implicit rules to uniquely determine all the possible casts to try?
What about constructing all types that can be cast to the target type using only const_cast, i.e. all "intermediate types"?
Given target type T, if static_cast doesn't work, identify all positions where one could add cv-qualifiers such that the resulting type can be cast back to T by const_cast1. Sketch of the algorithm: take the cv-decomposition ([conv.qual]/1) of T; each cvj can be augmented. If T is a reference, we can augment the referee type's cv-qualification.
Now add const volatile to all these places. Call the resulting type CT. Try static_casting the expression to CT instead. If that works, our cast chain is const_cast<T>(static_cast<CT>(e)).
If this doesn't work, there very probably is no conversion using static_cast followed by const_cast (I haven't delved into the deep corners of overload resolution (well I have, but not for this question)). But we could use brute force to repeatedly remove const/volatiles and check each type if we really wanted. So in theory, there is no ambiguity or underspecification; if there is some cast chain, it can be determined. In practice, the algorithm can be made very simple, because the "most cv-qualified" type we can construct from T is (assuredly) sufficient.

Is static_cast a template?

I am learning C++ templates, I found that the type conversion like static_cast<>, dynamic_cast<>, const_cast<> and reinterpret_cast<> looks like templates, though the book said they are all "operators". I want to know:
1)Whether these cast functions are written by templates?
2)If it is true, Where can I find the source code?
3)If it is not true, why they are all designed in the form of templates? is it possible to implement them by templates?
Whether these cast functions are written by templates?
No. As your book says, they're operators.
why they are all designed in the form of templates?
Like templates, their behaviour is partly specified using a compile-time type parameter. It makes sense to use the same syntax to do the same thing in a slightly different context.
is it possible to implement them by templates?
Using just the core C++ language, no.
It's possible that static_cast, const_cast and reinterpret_cast could be implemented by a combination of a C-style cast (which allows all these conversions), and C++11 type traits to restrict the conversions to those allowed in each case. However, some of those traits depend on magic that can't be implemented using the core language.
dynamic_cast needs to access the object's RTTI information; there's no way to do that other than through typeid or dynamic_cast itself.
static_cast etc are language keywords and, as such, are not templates.
They look like templates since that's the best functional form to express their functionality.
To an extent you can implement functions similar in form to these casts. For example, I define in some of my code a function integral_cast:
template<
typename T/*the desired type*/,
typename/*the source type*/ Y
> T integral_cast(const Y& y)
{
static_assert(false, "undefined integral_cast");
}
// Pass through for uint32_t
template<>
inline std::uint32_t integral_cast(const uint32_t& y)
{
return y;
}
/*and various other specialisations*/
This allows me to convert from one integral type to another in situations where I might overflow the destination type. The calling syntax is identical to the built in casts.

C++ casting for C-style downcasting

When working with a C API that uses C-style inheritance, (taking advantage of the standard layout of C-structs), such as GLib, we usually use C-style casts to downcast:
struct base_object
{
int x;
int y;
int z;
};
struct derived_object
{
base_object base;
int foo;
int bar;
};
void func(base_object* b)
{
derived_object* d = (derived_object*) b; /* Downcast */
}
But if we're writing new C++ code that uses a C-API like this, should we continue to use C-style casts, or should we prefer C++ casts? If the latter, what type of C++ casts should we use to emulate C downcasting?
At first, I thought reinterpret_cast would be suitable:
derived_object* d = reinterpret_cast<derived_object*>(b);
However, I'm always wary of reinterpret_cast because the C++ standard guarantees very little about what will happen. It may be safer to use static_cast to void*:
derived_object* d = static_cast<derived_object*>(static_cast<void*>(b))
Of course, this is really cumbersome, making me think it's better to just use C-style casts in this case.
So what is the best practice here?
If you look at the specification for C-style casts in the C++ spec you'll find that cast notation is defined in terms of the other type conversion operators (dynamic_cast, static_cast, reinterpret_cast, const_cast), and in this case reinterpret_cast is used.
Additionally, reinterpret_cast gives more guarantees than is indicated by the answer you link to. The one you care about is:
§ 9.2/20: A pointer to a standard-layout struct object, suitably converted using a reinterpret_cast, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa.
If you want to use a cast notation I think using the C++ type conversion operators explicitly is best. However rather than littering casts all over the code you should probably write a function for each conversion (implemented using reinterpret_cast) and then use that.
derived_object *downcast_to_derived(base_object *b) {
return reinterpret_cast<derived_object*>(b);
}
However, I'm always wary of reinterpret_cast because the C++ standard
guarantees very little about what will happen.
C++-style casts are no less safe than C-style casts, because C-style cast is defined in terms of C++-style casts.
5.4.4 The conversions performed by
— a const_cast (5.2.11),
— a static_cast (5.2.9),
— a static_cast followed by a const_cast,
— a reinterpret_cast (5.2.10), or
— a reinterpret_cast followed by a const_cast,
can be performed using the cast notation of explicit type conversion.
[...]
If a conversion can be interpreted in more than one of the ways listed above, the interpretation that
appears first in the list is used, even if a cast resulting from that interpretation is ill-formed.
The sad answer is that you can't avoid casts in code like you written, because the compiler knows very little about relations between classes. Some way or another, you may want to refactor it (casts or classes or the code that uses them).
The bottom line is:
If you can, use proper inheritance.
If you can't, use reinterpret_cast.
new C++ code that uses a C-API like this
Don't write new C++ code in a C style, it doesn't make use of the C++ language features, and it also forces the user of your wrapper to use this same "C" style. Instead, create a proper C++ class that wraps the C API interface details and hides them behind a C++ class.
should we continue to use C-style casts
No
or should we prefer C++ casts
Yes, but only when you have to.
Use C++ inheritance and virtual accessor functions (probably). Please show how you plan to use the derived object in func, this may provide a better answer for you.
If func expects to use the methods of the derived object, then it should receive a derived object. If it expects to use the methods of a base_object, but the methods are somehow changed because the pointer is to a derived_object, then virtual functions are the C++ way to do this.
Also, you want to pass a reference to func, not a pointer.
dynamic_cast, requires certain conditions to be met:
http://www.cplusplus.com/doc/tutorial/typecasting/
If you are just converting struct ptrs to struct ptrs and you know what you want, then static_cast, or reinterpret_cast may be the best?
However, if you truly are interested in writing C++ code, then the casts should be your last and final resort, since there are better patterns. The two common situations I would consider casting are:
You are interfacing with some event passing mechanism that passes a generic base class to an event handler.
You have a container of objects. The container requires it to contain homogenous types (i.e every element contains the same "thing"), but you want to store different types in the container.
I think dynamic_cast is exactly what you want.

What are the benefits of explicit type cast in C++?

What are the benefits of explicit type cast in C++ ?
They're more specific than the full general C-style casts. You don't give up quite as much type safety and the compiler can still double check some aspects of them for you.
They're easy to grep for if you want to try clean up your code.
The syntax intentionally mimics a templated function call. As a a result, you can "extend" the language by defining your own casts (e.g., Boost's lexical_cast).
Clarity in reading the code. There is not too much else of benefit, except for the cases where the compiler cannot infer the implicit cast at all, in which case you'd have to cast explicitly anyway.
The recommended way to cast in c++ is through dynamic_cast, static_cast, and the rest of those casting operators:
http://www.cplusplus.com/doc/tutorial/typecasting/
Notice that all typecasts are explicit in C++ and C. There are, in the language, no "implicit" typecasts. It's called "implicit conversions" and "explicit conversions", the latter of which are also called "casts".
Typecasts are most often used to inhibit warnings by the compiler. For instance if you have a signed and an unsigned value and compare them, the compiler usually warns you. If you know the comparison is correct, you can cast the operands to a signed type.
Another example is overload resolution, where type casts can be used to drive to the function to be called. For example to print out the address of a char, you can't just say cout << &c because that would try to interpret it as a C-Style String. Instead you would have to cast to void* before you print.
Often implicit conversions are superior to casts. Boost provides boost::implicit_cast to go by implicit conversions. For example the following relies on the implicit conversions of pointers to void*
cout << boost::implicit_cast<void*>(&c);
This has the benefit that it's only allowing conversions that are safe to do. Downcasts are not permitted, for example.
often used on void* to recover a implicitly known type. Especially common on embedded OS's for callbacks. This is a case where when you register for an event and maybe pass your "this" pointer as a context void*, then when the triggers it will pass you the void * context and you covert it back to the type the "this" pointer was.
Sometimes explicit casting avoids certain undesirable cirumstances by using explicit keyword.
class ExplicitExample
{
public:
ExplicitExample(int a){...}
}
ExplicitExample objExp = 'A';//No error.. call the integer constructor
Change as
explicit ExplicitExample(int a){ ... }
Now compile.
ExplicitExample objExp = 'A';
We get this error in VS2005.
error C2440: 'initializing' : cannot convert from 'char' to 'ExplicitExample'
Constructor for class 'ExplicitExample' is declared 'explicit'
To overcome this error, we have to declare as
ExplicitExample objExp = ExplicitExample('A');
It means as a programmer, we tell the compiler we know what we are calling. So compiler ignores this error.