0

Say I have a class C that I want to be able to implicitly cast to bool to use in if statements.

class C {
public:
    ...
    operator bool() { return data ? true : false; }
private:
    void * data;
};

and

C c;
...
if (c) ...

But the cast operator has a conditional which is technically overhead (even if relatively insignificant). If data was public I could do if (c.data) instead which is entirely possible and does not involve any conditionals. I doubt that the compiler will do any implicit conversion involving a conditional in the latter scenario, since it will likely generate a "jump if zero" or "jump if not zero" which doesn't really need any Boolean value, which the CPU will most likely have no notion of anyway.

My question is whether the typecast operator overload will indeed be less efficient than directly using the data member.

Note that I did establish that if the typecast directly returns data it also works, probably using the same type of implicit (hypothetical and not really happening in practice) conversion that would be used in the case of if (c.data).

Edit: Just to clarify, the point of the matter is actually a bit hypothetical. The dilemma is that Boolean is itself a hypothetical construct (which didn't initially exist in C/C++), in reality it is just integers. As I mentioned, the typecast can directly return data or use != instead, but it is really not very readable, but even that is not the issue. I don't really know how to word it to make sense of it better, the C class has a void * that is an integer, the CPU has conditional jumps which use integers, the issue is that abiding to the hypothetical Boolean construct that sits in the middle mandates the extra conditional. Dunno if that "clarification" made things any more clear though...

  • You don't need implicit cast to `bool` for that, `explicit` is enough. – Deduplicator Oct 31 '14 at 12:08
  • 1
    If data is usable as a boolean, you don't need to use a ternary. just `operator bool() { return data;}`. Regardless, a function like this is very likely to be inlined by the compiler since it's so trivial, so overloading `operator bool` and using `c.data` would likely produce the same machine code. – Karl Nicoll Oct 31 '14 at 12:08
  • @KarlNicoll - I am aware of that. It is not a practical issue, it's a matter of "principle", I mean returning a `void *` in a function that is supposed to return `bool` is kind of messy, even if "legal" –  Oct 31 '14 at 12:09
  • 2
    @KarlNicoll The data _may_ be technically usable as a `bool`, but it's not a `bool`, and implicit conversions make the code harder to read. It should be `return data != nullptr;`. – James Kanze Oct 31 '14 at 12:11
  • 3
    Since when is relieing on implicit conversions "messy"? – Deduplicator Oct 31 '14 at 12:11
  • @JamesKanze: Hope you don't forget `!= false` when testing a boolean then... – Deduplicator Oct 31 '14 at 12:13
  • @Deduplicator - you didn't quite get why I put it in quotes, did you? The question has to do with the fact that Boolean is purely hypothetical construct, and the potential overhead from abiding to it without the technical necessity to do so. –  Oct 31 '14 at 12:14
  • 1
    @JamesKanze - There's nothing wrong with doing it that way if you wish to be explicit (although in my experience you'll be hard pressed to find someone that didn't know what an implicit pointer->boolean conversion was). Regardless, this kind of stuff is very easy for a compiler to optimize away. It's a non-issue. – Karl Nicoll Oct 31 '14 at 12:14
  • @JamesKanze "data may be technically usable as a bool, but it's not a bool" - that's exactly what I mean. –  Oct 31 '14 at 12:16
  • @Deduplicator A boolean is a boolean; no implicit conversions involved. Comparing it to `false` just shows that you don't know what a boolean is. (Not comparing a pointer to `nullptr` also shows that you don't know what a pointer is.) – James Kanze Oct 31 '14 at 13:29
  • @KarlNicoll I think I know the implicit conversions pretty well, but I still have to stop and think about them when they are used. `!strcmp` to test if two C-style strings are equal is perhaps the worst, but `if ( p )`, rather than `if ( p != nullptr )` also makes me hesitate. – James Kanze Oct 31 '14 at 13:31
  • @user3735658 In the code you posted, you use `data` as if it were `bool`. – James Kanze Oct 31 '14 at 13:32
  • @JamesKanze: So, do you say implicit conversions are the devil, or did you just single out pointers? Your previous one read more like "always do an explicit comparison, irrespective of it changing things". – Deduplicator Oct 31 '14 at 13:38
  • @Deduplicator I'm saying that in general, implicit conversions make the code harder to read, at least if they are between "unrelated" types. (An implicit conversion of an `int` to `long` doesn't cause problems, because the "value" doesn't change.) – James Kanze Oct 31 '14 at 13:54

3 Answers3

3

My question is whether the typecast operator overload will indeed be less efficient than directly using the data member.

Only examining your compiler output - with the specific optimisation flags you'd like to use - can tell you for sure, and then it might change after some seemingly irrelevant change like adding an extra variable somewhere in the calling context, or perhaps with the next compiler release etc....

More generally, C++ wouldn't be renowned for speed if the optimisers didn't tend to handle this kind of situation perfectly, so your odds are very good.

Further, write working code then profile it and you'll learn a lot more about what performance problems are actually significant.

Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
3

It depends on how smart your compiler's optimizer is. I think they should be smart enough to remove the useless ? true: false operation, because the typecast operation should be inlined.

Or you could just write this and not worry about it:

operator bool() { return data; }

Since there's a built-in implicit typecast from void* to bool, data gets typecast on the way out the function.

I don't remember if the conditional in if expects bool or void*; at one point, before C++ added bool, it was the latter. (operator! in the iostream classes returned void* back then.)

Mike DeSimone
  • 41,631
  • 10
  • 72
  • 96
  • 1
    The conditional expression (in `if`, `while`, `for`, ...) is contextually converted to `bool`, which means an explicit conversion. – Deduplicator Oct 31 '14 at 12:16
  • 1
    FWIW, `bool` was only introduced a couple years before the C++98 standard, while iostream's conversions to `void*` persisted right up until C++11, largely because that practice - known as the "safe bool" idiom - avoided a couple issues with implicit conversion to `bool` - see e.g. [this question](http://stackoverflow.com/questions/1334858/why-dont-iostream-objects-overload-operator-bool) – Tony Delroy Oct 31 '14 at 15:43
1

On modern compilers these two functions produce the same machine code:

bool toBool1(void* ptr) {
    return ptr ? true : false;
}

bool toBool2(void* ptr) {
    return ptr;
}

Demo

So it really doesn't matter.

Anton Savin
  • 40,838
  • 8
  • 54
  • 90