Glen Fletcher
Glen Fletcher

Reputation: 654

C++ explicit integral user-defined conversion

I have a flags class witch is just a wrapper around an integer and I want to implement explicit conversion to to arbitrary integers types based on the conversion rules for the underlying integer type.

i.e.

say I have the class along the lines of (ignoring non-relevant members)

class Flags {
    unsigned int v;
    explicit operator unsigned int() { return v; }
}

could I still convert to an integral type other than int say by

unsigned long long iflags = static_cast<unsigned long long>(flags);

rather than

unsigned long long iflags = static_cast<unsigned int>(flags);

or would I need to explicitly define a conversion operator for every integral type to be able to do this?

Note I'm using C++14

I've read http://en.cppreference.com/w/cpp/language/cast_operator but can't see any thing specific to integral types which makes me think I need to explicit define all valid conversion which I want to avoid. I would also be happy with a template conversion function which will fail if conversion to the target type isn't possible, noting I know the max value of the internal integer i.e. all flag bits turned on, as a macro/constant FLAGS_MAX, if this is of any use.

Upvotes: 0

Views: 802

Answers (2)

R Sahu
R Sahu

Reputation: 206577

could I still convert to an integral type other than int say by

unsigned long long iflags = static_cast<unsigned long long>(flags);

No, you can't.

The above is equivalent to:

unsigned long long temp(flags);
unsigned long long iflags = temp;

The first line is wrong since flags cannot be implicitly converted to unsigned long long.

Given the definition of Flags, the only legal C++ method to initialize iflags is to use:

 unsigned long long iflags = static_cast<unsigned int>(flags);

If you remove the explicit qualifier from the conversion operator

class Flags {
    unsigned int v;
    public:
       operator unsigned int() { return v; }
}

then you can use

unsigned long long iflags = static_cast<unsigned long long>(flags);

Upvotes: 1

T.C.
T.C.

Reputation: 137320

That static_cast attempt falls under [expr.static.cast]/4, which roughly says that you can do static_cast<T>(e) if you can do T t(e); for some invented variable t (there's some fun dance in the wording to take care of guaranteed elision and C-style cast oddities, which we can ignore for our purposes).

That initialization is controlled by [dcl.init]/17.7, which says you do overload resolution on the conversion functions of Flags, with a pointer to [over.match.conv], which has this to say about candidates:

Those non-explicit conversion functions that are not hidden within [Flags] and yield type [unsigned long long] or a type that can be converted to type [unsigned long long] via a standard conversion sequence are candidate functions. For direct-initialization, those explicit conversion functions that are not hidden within [Flags] and yield type [unsigned long long] or a type that can be converted to type [unsigned long long] with a qualification conversion are also candidate functions.

Your explicit operator unsigned int() neither yields unsigned long long nor a type that can be converted to it via a qualification conversion (which is irrelevant here - that conversion only applies to pointer-y things); it is therefore not a candidate. Since the candidate set is empty, overload resolution fails, so the initialization is ill-formed, and so is the static_cast.

Upvotes: 1

Related Questions