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.
Related
C++11 provides standard <type_traits>.
Which of them are impossible to implement without compiler hooks?
Note 1: by compiler hook I mean any non-standard language feature such as __is_builtin....
Note 2: a lot of them can be implemented without hooks (see chapter 2 of C++ Template Metaprogramming and/or chapter 2 of Modern C++ Design).
Note 3: spraff answer in this previous question cites N2984 where some type traits contain the following note: is believed to require compiler support (thanks sehe).
I have written up a complete answer here — it's a work in progress, so I'm giving the authoritative hyperlink even though I'm cutting-and-pasting the text into this answer.
Also see libc++'s documentation on Type traits intrinsic design.
is_union
is_union queries an attribute of the class that isn't exposed through any other means;
in C++, anything you can do with a class or struct, you can also do with a union. This
includes inheriting and taking member pointers.
is_aggregate, is_literal_type, is_pod, is_standard_layout, has_virtual_destructor
These traits query attributes of the class that aren't exposed through any other means.
Essentially, a struct or class is a "black box"; the C++ language gives us no way to
crack it open and examine its data members to find out if they're all POD types, or if
any of them are private, or if the class has any constexpr constructors (the key
requirement for is_literal_type).
is_abstract
is_abstract is an interesting case. The defining characteristic of an abstract
class type is that you cannot get a value of that type; so for example it is
ill-formed to define a function whose parameter or return type is abstract, and
it is ill-formed to create an array type whose element type is abstract.
(Oddly, if T is abstract, then SFINAE will apply to T[] but not to T(). That
is, it is acceptable to create the type of a function with an abstract return type;
it is ill-formed to define an entity of such a function type.)
So we can get very close to a correct implementation of is_abstract using
this SFINAE approach:
template<class T, class> struct is_abstract_impl : true_type {};
template<class T> struct is_abstract_impl<T, void_t<T[]>> : false_type {};
template<class T> struct is_abstract : is_abstract_impl<remove_cv_t<T>, void> {};
However, there is a flaw! If T is itself a template class, such as vector<T>
or basic_ostream<char>, then merely forming the type T[] is acceptable; in
an unevaluated context this will not cause the compiler to go instantiate the
body of T, and therefore the compiler will not detect the ill-formedness of
the array type T[]. So the SFINAE will not happen in that case, and we'll
give the wrong answer for is_abstract<basic_ostream<char>>.
This quirk of template instantiation in unevaluated contexts is the sole reason
that modern compilers provide __is_abstract(T).
is_final
is_final queries an attribute of the class that isn't exposed through any other means.
Specifically, the base-specifier-list of a derived class is not a SFINAE context; we can't
exploit enable_if_t to ask "can I create a class derived from T?" because if we
cannot create such a class, it'll be a hard error.
is_empty
is_empty is an interesting case. We can't just ask whether sizeof (T) == 0 because
in C++ no type is ever allowed to have size 0; even an empty class has sizeof (T) == 1.
"Emptiness" is important enough to merit a type trait, though, because of the Empty Base
Optimization: all sufficiently modern compilers will lay out the two classes
struct Derived : public T { int x; };
struct Underived { int x; };
identically; that is, they will not lay out any space in Derived for the empty
T subobject. This suggests a way we could test for "emptiness" in C++03, at least
on all sufficiently modern compilers: just define the two classes above and ask
whether sizeof (Derived) == sizeof (Underived). Unfortunately, as of C++11, this
trick no longer works, because T might be final, and the "final-ness" of a class
type is not exposed by any other means! So compiler vendors who implement final
must also expose something like __is_empty(T) for the benefit of the standard library.
is_enum
is_enum is another interesting case. Technically, we could implement this type trait
by the observation that if our type T is not a fundamental type, an array type,
a pointer type, a reference type, a member pointer, a class or union, or a function
type, then by process of elimination it must be an enum type. However, this deductive
reasoning breaks down if the compiler happens to support any other types not falling
into the above categories. For this reason, modern compilers expose __is_enum(T).
A common example of a supported type not falling into any of the above categories
would be __int128_t. libc++ actually detects the presence of __int128_t and includes
it in the category of "integral types" (which makes it a "fundamental type" in the above
categorization), but our simple implementation does not.
Another example would be vector int, on compilers supporting Altivec vector extensions;
this type is more obviously "not integral" but also "not anything else either", and most
certainly not an enum type!
is_trivially_constructible, is_trivially_assignable
The triviality of construction, assignment, and destruction are all attributes of the
class that aren't exposed through any other means. Notice that with this foundation
we don't need any additional magic to query the triviality of default construction,
copy construction, move assignment, and so on. Instead,
is_trivially_copy_constructible<T> is implemented in terms of
is_trivially_constructible<T, const T&>, and so on.
is_trivially_destructible
For historical reasons, the name of this compiler builtin is not __is_trivially_destructible(T)
but rather __has_trivial_destructor(T). Furthermore, it turns out that the builtin
evaluates to true even for a class type with a deleted destructor! So we first need
to check that the type is destructible; and then, if it is, we can ask the magic builtin
whether that destructor is indeed trivial.
underlying_type
The underlying type of an enum isn't exposed through any other means. You can get close
by taking sizeof(T) and comparing it to the sizes of all known types, and by asking
for the signedness of the underlying type via T(-1) < T(0); but that approach still
cannot distinguish between underlying types int and long on platforms where those
types have the same width (nor between long and long long on platforms where those
types have the same width).
Per lastest boost documentation which is also a bit old but I think it's valid still
Support for Compiler Intrinsics
There are some traits that can not be implemented within the current C++ language: to make these traits "just work" with user defined types, some kind of additional help from the compiler is required. Currently (April 2008) Visual C++ 8 and 9, GNU GCC 4.3 and MWCW 9 provide at least some of the the necessary intrinsics, and other compilers will no doubt follow in due course.
The Following traits classes always need compiler support to do the right thing for all types (but all have safe fallback positions if this support is unavailable):
is_union
is_pod
has_trivial_constructor
has_trivial_copy
has_trivial_move_constructor
has_trivial_assign
has_trivial_move_assign
has_trivial_destructor
has_nothrow_constructor
has_nothrow_copy
has_nothrow_assign
has_virtual_destructor
The following traits classes can't be portably implemented in the C++ language, although in practice, the implementations do in fact do the right thing on all the compilers we know about:
is_empty
is_polymorphic
The following traits classes are dependent on one or more of the above:
is_class
Sorry for the newbie question, but I have a feeling I am missing something here:
If I have a certain class template which looks like this (basically the only way to pass a lambda to a function in C++, unless I am mistaken):
template<typename V, typename F>
class Something
{
public:
int some_method(V val, F func) {
double intermediate = val.do_something();
return func(intermediate);
}
}
By reading the implementation of this class, I can see that the V class must implement double do_something(), and that F must be a function/functor with the signature int F(double).
However, in languages like Java or C#, the constraints for the generic parameters are explicitly stated in the generic class signature, so they are obvious without having to look at the source code, e.g.
class Something<V> where V : IDoesSomething // interface with the DoSomething() method
{
// func delegate signature is explicit
public int SomeMethod(V val, Func<double, int> func)
{
double intermediate = val.DoSomething();
return func(intermediate);
}
}
My question is: how do I know how to implement more complex input arguments in practice? Can this somehow be documented using code only, when writing a library with template classes in C++, or is the only way to parse the code manually and look for parameter usage?
(or third possibility, add methods to the class until the compiler stops failing)
C# and Java Generics have similar syntax and some common uses with C++ templates, but they are very different beasts.
Here is a good overview.
In C++, by default template checking was done by instantiation of code, and requrements are in documentation.
Note that much of the requirements of C++ templates is semantic not syntactic; iterators need not only have the proper operations, those operations need to have the proper meaning.
You can check syntactic properties of types in C++ templates. Off the top of my head, there are 6 basic ways.
You can have a traits class requirement, like std::iterator_traits.
You can do SFINAE, an accidentally Turing-complete template metaprogramming technique.
You can use concepts and/or requires clauses if your compiler is modern enough.
You can generate static_asserts to check properties
You can use traits ADL functions, like begin.
You can just duck type, and use it as if it had the properties you want. If it quacks like a duck, it is a duck.
All of these have pluses and minuses.
The downside to all of them is that they can be harder to set up than "this parameter must inherit from the type Foo". Concepts can handle that, only a bit more verbose than Java.
Java style type erasure can be dominated using C++ templates. std::function is an example of a duck typed type eraser that allows unrelated types to be stored as values; doing something as restricted as Java is rarely worthwhile, as the machinery to do it is harder than making something more powerful.
C# reification cannot be fully duplicated by C++, because C#'s runtime environment ships with a compiler, and can effectively compile a new type when you instantiate at runtime. I have seen people ship compilers with C++ programs, compile dynamic libraries, then load and execute them, but that isn't something I'd advise.
Using modern c++20, you can:
template<Number N>
struct Polynomial;
where Number is a concept which checks N (a type) against its properties. This is a bit like the Java signature stuff on steroids.
And by c++23 you'll be able to use compile time reflection to do things that make templates look like preprocessor macros.
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.
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).
In C# 4.0, you can use the "dynamic" keyword as a placeholder for a type that is not known until runtime. There are certain corner cases where this is extremely useful behavior. Is it possible to emulate anything like this in C++, possibly using C++0x features or RTTI?
Not really. The closest you can get is a void *, but you still need to cast it to an appropriate type before you can use it.
Update:
Trying to build a duck-typed DSL that compiles to C++, basically.
You can go about this in at least two ways:
Union-based variant
struct MyType {
enum { NUMBER, STRING /* etc */ } type;
union {
double number;
string str;
};
};
Polymorphic class heirarchy
class MyType {
public:
/* define pure virtual operations common to all types */
};
class MyNumber : public MyType {
private:
double number;
public:
/* implement operations for this type */
};
C#'s dynamic feature is highly dependant on .NET's built-in reflection capabilities. As standard C++ offers next to no reflection support, there's no way you can get a similar behavior. RTTI will allow you to safely downcast pointers but that's pretty much it. You're still quite far to being able to enumerate fields and methods and invoke them dynamically.
As others already said this isn't possible in the general case but I think it would be informative to see why not.
There are two levels to the problem, the syntactic level and the semantic level.
On the syntactic level you have the following code:
dynamic d = /* something */;
d.Foo(bar); // Foo is unknown at compile time
In .NET dynamic is a compiler feature, what it does is instead of generating a function call it creates a call site which contains the function name and types of parameters (for overloading). This means that if you want to support dynamic you have to modify the compiler. It's true that template meta programming allows doing similar stuff but TMP is by its nature done at compile time and therefore won't be up to the job of supporting runtime invocation.
If you're not anal about the syntax then you may be able to support something like this:
dynamic d = /* something */;
d.invoke("Foo", bar);
On the semantic level
As #Trillian (cool user name BTW) said, dynamic relies on reflection, this isn't strictly true, you can specify how dynamic is implemented, and the default for CLR types is reflection, so the type that bound to a dynamic variable must support some sort of runtime inspection (e.g. COM's IDispatch). This isn't true for the general case in C++ but if you can narrow your support only to types that support (a known) type of inspection you can implement dynamic in C++ (sans the syntax as mentioned above).
It's not possible. Object sizes need to be known at compile-time, so the stack pointer can move by the appropriate number of bytes. If you don't declare the type, then the compiler won't know the size. C# gets around this problem by making all objects pointers.
This example on github provides one possible implementation, depending on your function complexity.
template <typename X, typename Y>
auto add(X x, Y y) -> decltype(x + y) {
return x + y;
}
add(1, 2); // == 3
add(1, 2.0); // == 3.0
add(1.5, 1.5); // == 3.0
I can't think of a possible code path where the type of a value is actually unknown all the way until run-time. Even if you are linking two modules together (dynamically, at run time), both are already compiled, and the types that they can return are also fully determined, and in fact encoded into the mangled names of the symbols the library exposes.
You can, however, defer knowledge of types until the code must actually be compiled. In C++0x, there's the auto keyword, which provides type inference from the expression used to initialize the variable, and in current C++, you can use templates, like so:
template<typename T>
T square(const T& someArg){
return T*T;
}
Edit: based on your comment on your question, You probably don't have a situation where the type is unknown. What's more likely is that the type is limited to one of a few (predefined) types. for that, you can use a union type, preferably using boost::variant