Search code examples
c++if-statementoperator-overloadingimplicit-conversion

Conversion operator and bool operator for if init expression


Snippet

#include <iostream>
#include <optional>

template <typename T>
struct W {
    operator T&() { return *t; }
    operator bool() const {
        std::cout << "called W bool operator\n";
        return t != nullptr;
    }

    T* t;
};

int main() {
    int x = 42;
    W<int> w{};
    w.t = &x;

    if (auto w_value = w) {
        std::cout << "w_value " << w_value << "\n";
    } else {
        std::cout << "w is empty" << "\n";
    }

    return 0;
}

Code is here godboldt

What I want here is that in if (auto w_value = w) w should be contextually convertible to bool, such that the assignment works.

This works as expected if the line operator T&() { return *t; } will be commented out.

But when this line is enabled, the bool conversion operator will not be called.

Is there a way to make this code work, such that if w converts to true, then a reference to t will be assigned in the if-init expression?

I have c++20 at disposal.


Solution

  • Ted has done a great job of explaining why operator bool() const isn't contextually called inside the if.

    Other ways to overcome that

    1. define a non-const overload

      explicit operator bool() {
        std::cout << "called W bool non-const operator\n";
        return t != nullptr;
      }
      
    2. Use deduced-this from later C++ standard to define all the const, non-const, volatile, lvalue, and rvalue variations at once

      template<typename Self>
      explicit operator bool(this Self&& self) {
        std::cout << "called deduced-W bool operator\n";
        return self.t != nullptr;
      }