読者です 読者をやめる 読者になる 読者になる

C++0x explicit bool

C++

スマートポインタのようなクラスを作成する場合、if文でヌルポインタかどうか判定できるようにするために
operator boolをオーバーロードします。

template <class T>
class smart_ptr {
    T* p_;
public:
    operator bool() const
    {
        return p_ != 0;
    }
};

smart_ptr<int> p;
    
// OK
if (p) {
    // ポインタは有効
}
else {
    // ポインタは無効
}

しかし、この方法では以下のような意味のないコードもコンパイルが通ってしまいます。

float f = p;
int x = p + 1;
cout << p << endl;

C++03には、この問題を解決するために"conversion to unspecified bool"というイディオムがあります。
これを使用すると、if文での使用を許可し、上記のような意味のないコードはコンパイルエラーにすることができます。
(boost::shared_ptr等で使用されています)

template <class T>
class smart_ptr {
    T* p_;
public:
    smart_ptr(T* p = 0)
        : p_(p) {}

    typedef smart_ptr<T> this_type;
    typedef T* (this_type::*unspecified_bool_type)() const;
    
    operator unspecified_bool_type() const
    {
        return p_ ? &this_type::get : 0;
    }

    T* get() { return p_; }
};

C++0xでは、explicit conversionを使用してexplicit operator boolをオーバーロードすることで、
"conversion to unspecified bool"イディオムを使用しなくてもよくなります。

template <class T>
class smart_ptr {
    T* p_;
public:
    explicit operator bool() const
    {
        return p_;
    }
};

smart_ptr<int> p;
    
// OK
if (p) {
    // ポインタは有効
}
else {
    // ポインタは無効
}

float f = p;       // エラー!
int x = p + 1;     // エラー!
cout << p << endl; // エラー!

ただし、このままではsmart_ptrと0リテラルとの比較がコンパイルエラーになってしまいます。

if (p == 0) { // エラー!
}

これを回避するため、C++0xのスマートポインタ(shared_ptr, unique_pr)には、nullptrを受け取るコンストラクタが用意されます。

shared_ptr(nullptr_t) : shared_ptr() {}
unique_ptr(nullptr_t) : unique_ptr() {}


N2435 Explicit bool for Smart Pointers

C++0x言語拡張まとめ