I have a Flags
class that behaves similarly to std::bitset
that is replacing bitpacked integers in an older codebase. To enforce compliance with the newer class, I want to disallow implicit conversion from int
types.
enum class Flag : unsigned int {
none = 0,
A = 1,
B = 2,
C = 4,
//...
};
class Flags {
public:
Flags();
Flags(const Flag& f);
explicit Flags(unsigned int); // don't allow implicit
Flags(const Flags&);
private:
unsigned int value;
};
I would like to allow implicit construction and assignment only from the Flag
and Flags
types. However, I would still like some function calls that take a Flags
parameter to accept a literal 0
, but not other integers:
void foo(const Flags& f);
foo(Flags(0)); // ok but ugly
foo(1); // illegal because of explicit constructor
foo(0); // illegal, but I want to allow this
Is this possible? To allow 0
to be implicitly converted while disallowing other values?
Implicit conversions: No special syntax is required because the conversion always succeeds and no data will be lost. Examples include conversions from smaller to larger integral types, and conversions from derived classes to base classes.
"It is possible for implicit conversions to lose information, signs can be lost (when signed is implicitly converted to unsigned), and overflow can occur (when long long is implicitly converted to float)."
An implicit conversion is when SQL Server must automatically convert a data type from one type into another when comparing values, moving data, or combining values with other values. When these values are converted, during the query process, it adds additional overhead and impacts performance.
Implicit conversions are not visible to the user. SQL Server automatically converts the data from one data type to another. For example, when a smallint is compared to an int, the smallint is implicitly converted to int before the comparison proceeds.
One approach:
Add a constructor which takes void*
.
Since literal 0
is implicitly convertible to a void*
null pointer, and literal 1
isn`t, this will give the desired behavior indicated. For safety you can assert that the pointer is null in the ctor.
A drawback is that now your class is constructible from anything implicitly convertible to void *
. Some unexpected things are so convertible -- for instance prior to C++11, std::stringstream
was convertible to void*
, basically as a hack because explicit operator bool
did not exist yet.
But, this may work out fine in your project as long as you are aware of the potential pitfalls.
Edit:
Actually, I remembered a way to make this safer. Instead of void*
use a pointer to a private type.
It might look like this:
class Flags {
private:
struct dummy {};
public:
Flags (dummy* d) { ... }
...
};
The literal 0
conversion will still work, and it's significantly harder for some user-defined type to accidentally convert to Flags::dummy *
unintentionally.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With