简体   繁体   中英

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.

ie

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 ie all flag bits turned on, as a macro/constant FLAGS_MAX , if this is of any use.

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);

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM