What is the difference between static_cast and Implicit_cast? - c++

What is implicit_cast? when should I prefer implicit_cast rather than static_cast?

I'm copying over from a comment i made to answer this comment at another place.
You can down-cast with static_cast. Not so with implicit_cast. static_cast basically allows you to do any implicit conversion, and in addition the reverse of any implicit conversion (up to some limits. you can't downcast if there is a virtual base-class involved). But implicit_cast will only accept implicit conversions. no down-cast, no void*->T*, no U->T if T has only explicit constructors for U.
Note that it's important to note the difference between a cast and a conversion. In the following no cast is going on
int a = 3.4;
But an implicit conversion happens from double to int. Things like an "implicit cast" don't exist, since a cast is always an explicit conversion request. The name construct for boost::implicit_cast is a lovely combination of "cast using implicit conversions". Now the whole implementation of boost::implicit_cast is this (explained here):
template<typename T> struct identity { typedef T type; };
template<typename Dst> Dst implicit_cast(typename identity<Dst>::type t)
{ return t; }
The idea is to use a non-deduced context for the parameter t. That will avoid pitfalls like the following:
call_const_version(implicit_cast(this)); // oops, wrong!
What was desired is to write it out like this
call_const_version(implicit_cast<MyClass const*>(this)); // right!
The compiler can't deduce what type the template parameter Dst should name, because it first must know what identity<Dst> is, since it is part of the parameter used for deduction. But it in turn depends on the parameter Dst (identity could be explicitly specialized for some types). Now, we got a circular dependency, for which the Standard just says such a parameter is a non-deduced context, and an explicit template-argument must be provided.

Prefer implcit_cast if it is enough in your situation. implicit_cast is less powerful and safer than static_cast.
For example, downcasting from a base pointer to a derived pointer is possible with static_cast but not with implicit_cast. The other way around is possible with both casts. Then, when casting from a base to a derived class, use implicit_cast, because it keeps you safe if you confuse both classes.
Also keep in mind that implicit_cast is often not needed. Using no cast at all works most of the time when implicit_cast does, that's where 'implicit' comes from. implicit_cast is only needed in special circumstances in which the type of an expression must be exactly controlled, to avoid an overload, for example.

implicit_cast transforms one type to another, and can be extended by writing implicit cast functions, to cast from one type to another.
e.g.
int i = 100;
long l = i;
and
int i = 100;
long l = implicit_cast<long>(i);
are exactly the same code
however you can provide your own implicit casts for your own types, by overloading implicit_cast like the following
template <typename T>
inline T implicit_cast (typename mpl::identity<T>::type x)
{
return x;
}
See here boost/implicit_cast.hpp for more
Hope this helps
EDIT
This page also talks about implicit_cast New C++
Also, the primary function of static_cast is to perform an non changing or semantic transformation from one type to another. The type changes but the values remain identical e.g.
void *voidPtr = . . .
int* intPtr = static_cast<int*>(voidPtr);
I want to look at this void pointer, as if it was an int pointer, the pointer doesn't change, and under the covers voidPtr has exactly the same value as intPtr.
An implicit_cast, the type changes but the values after the transformation can be differnet too.

Implicit conversions, explicit conversions and static_cast are all different things. however, if you can convert implicitly, you can convert explicitly, and if you can convert explicitly, you can cast statically. The same in the other direction is not true, however. There is a perfectly reasonable relationship between implicit casts and
static casts. The former is a subset of the the latter.
See section 5.2.9.3 of the C++ Standard for details
Otherwise, an expression e can be
explicitly converted to a type T using
a static_cast of the form static_-
cast(e) if the declaration T t(e);
is well-formed, for some invented
temporary variable t (8.5).
C++ encourages use of static_casts because it makes the conversion 'visible' in the program. Usage of casts itself indicates some programmer enforced rule which is worth a look so better use static_cast.

Related

Dynamic convertibility type trait

Is it possible to enumerate a list of types to which a type can be converted to? Or would this require a technique similar to static reflection?
struct a {
operator int() const
{ return i; }
explicit operator float() const
{ return f; }
int i;
float f;
};
// enumerated type list for type 'a': tuple<int, float>
One of the things I would like to be able to do—which is related to this but with a somewhat narrower scope—is to check if a type is convertible to, let's say, an integral type, without having to explicitly list them.
The only way I'm able to do this now, is to create a tuple-like type-list of all those integer types, throw it in std::is_convertible and expand them within a std::conjunction. But I would really prefer to use a way which doesn't require me write out all the types of a specific type class. I'm specifically looking for a solution that is compatible with C++17 but if that is not possible or is simply too cumbersome, a C++20 solution is acceptable too.
The first part of my question seems to be well answered by Igor Tandetnik and Barry. Enumerating all of the types to which a type can be converted to would be undesirable for the reasons they have laid out. Enumerating the non-templated user-defined converion operators of a type could be useful but that would require someting like static reflection, which isn't possible for the time being.
Regarding the second part of my question, it seems that there are some nuances involved with type conversions between arithmetic types. Since they are all convertible to each other, finding the type trait that fits my needs maybe requires a different approach. I've decided to list a couple examples to better describe the requirements of this type trait.
#include <type_traits>
#include <utility>
struct a {
operator int() const
{ return i; }
explicit operator float() const
{ return f; }
int i;
float f;
};
// this succeeds, but instead of explicitly writing out 'int' I would like to
// express my intent and write someting as 'any_integral_type' (note: I
// understand that integral types might be too narrow to properly detect,
// so 'any_arithmetic_type' could be acceptable too) and I would
// like to do so without listing all of the integral types by hand
static_assert(std::is_convertible_v<a, int>);
struct b {
int i;
float f;
};
// the difference between type 'a' and type 'b' seems rather obvious and
// I would like to have a type trait that can express that. how to write
// 'assert that b cannot be converted to any type that belongs to the
// std::integral_types' without explicitly writing 'int'?
static_assert(not std::is_convertible_v<b, int>);
// another idea is to use the unary addition operator to force the implicit
// conversion, this way we don't have to be upfront about which type to convert
// to, but this runs into ambiguity issues when there is more than one viable
// conversion operator (e.g.: when operator float isn't marked explicit)
static_assert(std::is_integral_v<decltype(+std::declval<a>())>);
Live example.
Is it possible to enumerate a list of types to which a type can be converted to?
No. Such a list of types is infinite. For instance, your a is convertible to int and float, yes. But also short and double and char and so forth, as far as obvious things go.
But then also std::any because it's copyable. And std::optional<a>. And std::variant<a>. And then std::variant<a, T> for all types T that are not a or a const (even if a is convertible to T, like int). Which is an obviously infinite list, even by itself. And then std::variant<a, T1, T2>, etc.
So not only is such a list of types infinite, but it's uncountably infinite.
Or would this require a technique similar to static reflection?
I suspect what you actually are asking for is a very narrow question: Given a type T, what are all of its conversion functions? For those conversion functions that are not functinon templates (you can't really enumerate template <typename T> operator T() const; for instance), then yes -- static reflection would let you enumerate that list.
But note that that list is just going to be the list of types that T has conversion functions into. That list is not the list of types that T is convertible to. Just a subset thereof.

When is a pointer-to-array convertible to a pointer-to-array of different type?

I was checking out the cppreference documentation for std::unique_ptr and noticed that C++17 seems to have made some interesting changes. In particular, the specialization for std::unique_ptr<T[]> now accepts template arguments where it previously only accepted std::unique_ptr::pointer arguments. For example, here is a declaration for one of the reset member functions of std::unique_ptr<T[]>:
template <typename U> void reset(U p);
The site states that:
Behaves the same as the reset member of the primary template, except that it will only participate in overload resolution if either
U is the same type as pointer, or
pointer is the same type as element_type* and U is a pointer type V* such that V(*)[] is convertible to element_type(*)[].
I'm assuming that this was done for safety - you wouldn't want to perform delete[] on a pointer to an array of derived type that was assigned to a pointer to its base type (prior to C++17 this was marked as deleted). As expected, this code compiles fine:
#include <type_traits>
struct foo {};
struct bar : public foo {};
static_assert(!std::is_convertible_v<bar(*)[], foo(*)[]>);
What's interesting, however, is that the following does not compile, failing both static_asserts:
#include <type_traits>
struct foo {};
struct bar : public foo {};
static_assert(std::is_convertible_v<bar*(*)[], foo*(*)[]>);
static_assert(std::is_convertible_v<std::unique_ptr<bar>(*)[], std::unique_ptr<foo>(*)[]>);
Why is that? In what scenario will this overload be used?
This is basically a way of saying "you can pass a less const-y pointer if it's safe to do so", e.g., int* p = /*...*/; unique_ptr<const int []> up; up.reset(p);
For different types U and V, the only case where U(*)[] is (implicitly) convertible to V(*)[] is by a qualification conversion, i.e., when you are adding const/volatile at the right places in the type. The exact rules are complicated (because they handle arbitrarily nested pointers/pointer-to-members/arrays; click the link if you want to know), but they essentially allow conversion only when it's safe; the specification of unique_ptr then leverages that fact so that it doesn't have to redefine "safe", at the cost of making the intent a little more cryptic.
struct foo {};
struct bar : public foo {};
In this trivial case, it's quite likely that the value representation of a foo* is exactly the same as that of a bar*, so it could be possible to convert between arrays of them. However, as soon as bar gets more complex, it no longer holds. Consider this:
struct foo {};
struct qux {};
struct bar : qux, foo {};
Now, a bar* is implicitly convertible to a foo*, but that conversion does not keep its exact value: it requires an offset from qux to foo.
Likewise, as soon as virtuals, multiple access control levels, etc. enter the picture, the address of the base class subobject can become different from that of the most derived object. Such pointers can even be of different size(1).
This is why there is only a limited set of cases where a derived* can be used as a base* without a value-changing conversion. My guess is that making allowances for the limited case would complicate the standard for little benefit, so conversions between such pointer arrays are simply disallowed.
(1) It's a bit of an obscure case, but it could happen if the C++ compiler was constrained by a poorly designed C ABI. This answer discusses such a situation.

call of template member function

If I have a class
class A {
template<class T>
void foo(T t);
};
what is the difference / the way of the book to call foo?
a.foo(t)
or
a.foo<X>(t)
?
a.foo(t) will basically deduce T to the type of t. If this is fine with you, use this.
a.foo<X> will force T to be X and the correctness of the expression now depends on if t is convertible to X. Sometimes you desire this, if you want t to be converted to X, but you could always write this as a.foo(X{t}). The second form is not entirely equivalent, since it also allows explicit conversions.
In the second variant, X may not be the type of t. E.g., if t is a float, but you say a.foo<int>(t), no floating variant will be deduced, but rather the integer-variant (if not exists already), and a float-to-int conversion will happen.
If the types are identical, there is no difference. However, one never knows for the whole lifetime of the code whether the types never change.

Convert scoped enum to int

Why cannot a scoped enum be converted to int implicitly? If I have
enum class Foo:uint32_t{...};
Then I know that the integers covered by Foo is a subset of those covered uint32_t, so I should always be safe. Am I missing some quirk here? The opposite cannot be safe though.
As LightnessRacesinOrbit explains in his answer, the whole purpose of scoped enums is to disallow implicit conversion to the underlying type.
You can convert them explicitly via a static_cast, but if what you desire is the ability to specify an underlying type, while allowing implicit conversions, you can do so with regular enums too, just remove the class keyword from the definition.
enum class Foo1 : uint32_t{ THING };
enum /*class*/ Foo2 : uint32_t{ THING };
uint32_t conv1 = static_cast<uint32_t>(Foo1::THING);
uint32_t conv2 = Foo2::THING; // <-- implicit conversion!
Just because such a conversion can always succeed doesn't mean you want it to be implicit.
The entire purpose of scoped enums is that they are distinct types that won't lead to confusing results during overload resolution.
Being explicit is good.

C++ Types Impossible to Name

While reading Wikipedia's page on decltype, I was curious about the statement,
Its [decltype's] primary intended use is in generic
programming, where it is often
difficult, or even impossible, to name
types that depend on template
parameters.
While I can understand the difficulty part of that statement, what is an example where there is a need to name a type that cannot be named under C++03?
EDIT: My point is that since everything in C++ has a declaration of types. Why would there ever be a case where it is impossible to name a type? Furthermore, aren't trait classes designed to yield type informations? Could trait classes be an alternative to decltype?
The wikipedia page you link has a perfect example:
int& foo(int& i);
float foo(float& f);
template <class T> auto transparent_forwarder(T& t) −> decltype(foo(t)) {
return foo(t);
}
Note that foo(int&) returns int& (a reference type) while foo(float&) returns float (a nonreference type). Without decltype, it's impossible within the template to specify a type which represents "the return type of the function foo which takes an argument t of type T".
In this example, it's not a particular concrete type which is impossible to express -- either int& or float are individually expressible -- but a higher level generic class of types.
EDIT: and to answer your comment to another answer, this example is inexpressible in C++03. You cannot have a function template which will wrap any function T1 foo(T2) and match both argument and return type of the wrapped function.
There are types in C++0x (and in C++03, but less often) that cannot be named explicitly, such as the type decltype(f) after the declaration auto f = [](int x) -> int {return x;};. You would need to typedef that decltype result to something to get a name at all. Traits classes can be used for determining return types, but they are messy, and the user needs to duplicate all of their function overloads with traits class overloads; that is difficult to do correctly for cases such as functions applying (through implicit conversion of pointers) to all subclasses of a given base class.
As you pointed out, the type if it exist is known by the compiler, otherwise it wouldn't exist. However, it is not always readily or even accessible to the programmer in C++03.
N1607 mention the following in its conclusion:
In C++2003, it is not possible to
express the return type of a function
template in all cases. Furthermore,
expressions involving calls to
function templates commonly have very
complicated types, which are
practically impossible to write by
hand
The question is how do we access this type as a programmer. This is not always a trivial process, often impracticable. It is increasingly complex when you have an expression for which you desire to know the result type. You would have to break it into pieces in order to figure the result types. It is not possible to simplify this process using templates (not without evaluating the expression anyhow). Breaking the expression will be error-prone, tedious and a nightmare to maintain. Think of this code:
x.g()[b.a(e)]->f();
With C++98/TR1, it is often infeasible to name types that depend on template parameters. Traits offers us so much information, but eventually decltype is a much cleaner solution to many problems. A lot of the information available to you when meta programming is only available because libraries, such as boost or loki, use several tricks hidden in the dark corners of the C++98 language.
Of course this is irrelevant to your question but I believe that it is worthy to mention that C++98 compilers already have mechanics to know these types. This is exactly what sizeof offers, except that it returns you a size. decltype reuse some of this functionality and solves these problems with greater elegance.
As for a different (academic) example:
struct Foo
{
struct
{
int x;
} bar;
};
template<typename T>
void
f(const T& t)
{
// C++03, How can I name the type of T::bar ?
// C++0x
// decltype(t.bar) cpy;
// Do stuff with our local cpy
}
int
main()
{
f(Foo());
}