Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Allowing implicit conversion for a single value

Tags:

c++

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?

like image 818
Rakurai Avatar asked Jun 13 '17 01:06

Rakurai


People also ask

What is the example of implicit conversion?

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.

Can there be loss of data as a result of an implicit conversion?

"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)."

Does implicit data type conversion improve performance?

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.

What is implicit data conversion?

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.


1 Answers

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.

like image 154
Chris Beck Avatar answered Oct 01 '22 14:10

Chris Beck