2
votes

I have a function call to some_func that takes int as argument.

int some_func(int);

class S {
public:
  S(int v) {
   a = v;
   }
  ...
 operator bool() const {
   return true;
 }
int a;
};  // class S doesn't define any "operator int"
S obj;
int x = some_func(obj); // some_func expected an int argument

In the above code, some_func expected int argument but is called with an object of type S. So it needs to convert it to "int".

But why is it using "operator bool"? Shouldn't it produce compile error saying no correct conversion method to int is specified for class S?

If I remove operator bool definition, then the program doesn't compile and gives an error about argument type mismatch in some_func call.

4
A bool value is implicitly convertible to an int with the value 0 (for false) or 1 (for true). See e.g. this implicit conversion reference (especially the section about integral promotion) for more information. - Some programmer dude
i guess i know the general idea behind promotion of bool to int and implicit conversion. But this is subtler: there is an implicit conversion from "S" to int (step-1), but the implicit conversion operator is not available (showstopper issue). So another operator (operator bool()) is being used because 'bool' can be promoted to int (step-2). Step-1 can't occur due to showstopper issue....(continued..) - Joe Black
(..continued) I think C++ doesn't specify what promotion of operator bool instead of just bool (i.e. when implicit conversion operator can somehow be used to make the conversion of "S"-> bool -> int work). where does integral promotion alone fully covers it? - Joe Black
To prevent the implicit conversion use explicit operator bool() - available since C++11. - zett42

4 Answers

4
votes

C++ has implicit conversions. By defining the conversion operator operator bool() you have made S implicitly convertible to bool. This is a user defined conversion. A conversion can consist of a sequence of conversions (only one of which may be user defined).

While there is no direct conversion from S to int, there is a built-in conversion from bool to int (this is an integer promotion, true is converted to 1 and false to 0). Therefore the conversion sequence S -> bool -> int is valid and therefore S is implicitly convertible to int.


PS. If you wanted to prevent the implicit conversion from bool when calling that function, you could declare a deleted overload that would be preferred by the overload resolution:

int some_func(bool) = delete;
3
votes

Bool and Int both are data-types. Data types can be converted either implicitly or explicitly. Implicit conversions are not visible to the user.

When you are defining:

operator bool() const {
   return true;
 }

Then the S is implicitly converted to bool. You can explicitly convert it to int. But note that while explicit conversion keep in mind the range of bytes and don't convert larger size data-types to smaller otherwise you will loose data as some bytes (larger datatype - smaller datatype) would be truncated.

In your problem the integers are converted to boolean(implicit conversion) Here the numbers other than 0 will be stored as true that is in the number form as 1 and the number 0 itself would be trated as false and hence will be stored as 0.

You can prevent this implicit conversion by defining your own explicit operator. See here or you can declare a delete overload.

See here for similar problem. I guess you will learn something there in the solutions that you seeking to.

1
votes

Whenever the compiler might need to convert an expression to another type, in particular for each argument of a function call, it attempts:

  1. An optional standard conversion sequence.
  2. An optional user-defined conversion.
  3. An optional standard conversion sequence.

A standard conversion sequence is one defined by the language, like arithmetic-to-arithmetic conversions, pointer conversion, etc. A user-defined conversion is one involving a constructor that can take one argument or a conversion function like your S::operator bool().

So in your example, it succeeds by finding no standard conversion, followed by your S::operator bool() user-defined conversion, followed by the standard conversion from bool to int.

For more gory details, see the cppreference page on implicit conversions.

0
votes

A boolean is internally represented as an integer.

true is defined to be 1 (basically everything except 0) and false is defined to be 0.

So it is possible to do something like this:

if(true+false+true) will result in if(2) which will be true since only if(0) would be false.