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.
Related
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.
I recently came across this piece of code and I'm wondering why it works. Enum declaration:
enum BuildResult {
RESULT_ERROR,
RESULT_SUCCESS
};
Later, this Enum is used in an if statement (ignore the fact that it could instead be RESULT_ERROR):
if (!objectHere->build_result == ClassNameHere::RESULT_SUCCESS)
I was not aware that you could use the not operator ! to flip the value of an Enum. Does this only work with Enums that have two states? Are there other kinds of implicit operators that can be used with Enums? I did find this question about manually declaring operators, but it doesn't seem to mention any implicit operators for enums.
The enum is implicitly casted to bool. When you flip it, it is no longer an enum type, but a boolean pr-value.
If you replace enum with enum class, which is type safe, this conversion is no longer possible.
When simple enum declaration is used, enum rvalues behave exactly like integers. You can even specify the type of the integer:
enum myEnum : uint32_t { NOT, TYPE, SAFE };
(note the implicit values of an enum: {NOT=0, TYPE=1, SAFE=2})
For one who has never written a line of C++11, and who has, at the moment, no opportunity to program in C++11, can you, in one short paragraph., tell me:
What is an "enum class" and why do we need it?
enum class is called a scoped enumeration. It prevents polluting the namespace where the enumeration appears with the names of the enumerators.
In C++03, you could do effectively the same thing by putting the enum inside a dedicated class. Perhaps that's the source of the syntax, which is a bit confusing.
Another difference is that the enumerators of such a type don't convert implicitly to int (static_cast<int> is required). This may be seldom needed but it makes it safe to overload a function taking an int argument with one taking enum type. You can be sure the int won't be called by accident. Or you can define pseudo-integral types with dedicated operator functions, and be sure that built-in operators won't interfere.
It's a bit annoying that these two unrelated differences come in the same package, and that you can't get an unscoped enumeration with no implicit conversion, but generally both changes are Good Things and enum class is a good default practice in C++11.
EDIT: A scoped enumeration is defined like this:
enum class duck { huey, dewey, louie };
and must be used with the scope resolution operator :: like this:
duck culprit = duck::huey; // or "auto culprit" to avoid redundancy
Note that the :: operator also works with C++03 unscoped enumerations, so the second line above would work even if the first was missing class.
This might be excessive detail, but class does not go into the elaborated-type-specifier if forward declaring the enumerated type, as in
void quack( enum duck whom ); // not "enum class"
However, there is a construct new in C++11, the opaque-enum-declaration, which does include the class keyword and defines a complete type.
enum duck; // duck is declared as incomplete type
enum class duck; // duck is now complete type; underlying type defaults to int
The keyword struct can be substituted for class with no semantic difference.
You can explicitly specify the storage type when the data size is important (packing it in a struct perhaps).
The enumeration values are scoped within the name of the enum only; before c++11 they leaked into the enclosing scope.
I seem to recall the conversion rules were also changed somewhat...
In relation to point one 1, the storage size of enums would change before C++11 depending on the largest value assigned to an enumeration. Usually it doesn't matter so much, but when it does you have to resort to ugly hacks to force the size.
As for point 3, in C++11 enums are not implicitly convertible or comparable to ints or other enum types: useful for avoiding function overloading headaches and other implicit conversion gotchas.
Personnally I have used it in a tcp based messaging protocol: many of the fields were enum values that I needed to encode inside one byte only, so as to respect the messaging interface..
All my enums were simply defined this way:
enum class EnumFieldA : unsigned char { eValProperty1, eValProperty2};
enum class EnumFieldB : unsigned char { eValProperty1, eValProperty2, eValProperty3};
enum class EnumFieldC : unsigned char { eValProperty1, eValProperty2, eValProperty3, eValProperty4};
...
there are also plenty of thorough answers in this SO question.
At first I was confused by your question, but I think you want to know the difference between c++ enum and that in c++11. As best as I can understand, in the later, you have strongly typed enums which allows you to scope your them. I think this explains it well. CHEERS
C++11 adds enum classes, which are stronger-typed enums - values of enum classes will not be implicitly converted to values of other enum classes or integers, and forward-declarations are permitted by virtue of an explicit size specifier.
Is it possible to pass values of such enumerations to varargs functions and remain within standards-defined behavior? Within implementation-defined behavior?
Yes, you can. 5.2.2/7 explicitly allows arguments of any enumeration type. Unscoped enum values are integer promoted, but scoped enums (the enum class ones) are not.
Of course you still have to be careful in the implementation of the function.
I think the answer is that it can be safe:
VA_ARGS requires arguments to be POD, that hasn't changed as far as I'm aware.
I can't see any reason why:
enum class foo { bar=1 };
Wouldn't meet the requirements for POD-ness though.
As you throw away some type information when using varargs (that's why it's strongly discouraged for non POD types) you will just receive the underlying type at the other end of your varargs using function. The default is int but you can change that (e.g. enum class MyEnum : char { ... };)
Corrected: varargs does indeed not throw away all type information and if you use POD data type you should be quite safe.
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.