キャスト演算子のオーバーロード

私が C++ を触り始めてから随分長い間知らなかった記述の一つにキャスト演算子オーバーロードがあります.キャスト演算子は,関数などで求められている型(引数など)と実際に指定したクラスの型が違う場合,「求められている型にキャストする」と言う動作を定義するためのメソッドです.定義の仕方は,"operator 型名() { ... }" と若干トリッキーな記述方法になっています.

#include <iostream>
#include <string>

class foo {
public:
    operator int() const { return 100; }
    operator std::string() const { return std::string("Hello"); }
};

// 適当な関数
void put_int(int x) { std::cout << x << std::endl; }
void put_str(const std::string& x) { std::cout << x << std::endl; }

int main() {
    foo a;
    put_int(a); // 100 と出力される
    put_str(a); // "Hello" と表示される
    return 0;
}

使用方法としては,例えば,マルチ文字列リテラル - TrickDiary などがあります(個人的に一番うまいと思ったもの).

template<class char_T, class wide_T>
class TX_literal_holder
{
public:
    char_T char_literal;
    wide_T wide_literal;
    TX_literal_holder(char_T a_char_literal, wide_T a_wide_literal)
        :char_literal(a_char_literal), wide_literal(a_wide_literal) {}
    
    operator char_T () const { return char_literal; }
    operator wide_T () const { return wide_literal; }
};
マルチ文字列リテラル - TrickDiary

テンプレートを使用して char と wchar_t のどちらにも対応すると言うコードをしばしば書きたくなりますが,この際に文字列リテラルの扱いが問題となります(char 型の場合は "hoge",wchar_t 型の場合は L"hoge" と書き分けなければならないため).これを上記のようなクラスを利用する事によって,VC++ の _T マクロと似たような働きをする関数(またはマクロ)を作成することができます.

この他の例としては,スマートポインタクラスに bool のキャスト演算子を定義して,ポインタと同じような利用方法(if (!p) { ... } のような形で,値が存在するかどうかを判定する)を提供すると言うものがよく知られています.

ここ最近では,http://d.hatena.ne.jp/tt_clown/20091009/1255047431 で作成したラッパクラスが void foo(const std::vector& x) { ... } のような関数の引数として指定できないのは不便だなぁと言うことで,下記のようなキャスト演算子を定義しました.

template <class Type>
class container_accessor : public noncopyable<container_accessor<Type> > {
public:
    explicit container_accessor(Type& v) : v_(v) {}
    virtual ~container_accessor() throw() {}
    
    operator Type&() { return v_; }
    operator const Type&() const { return v_; }
    
    ...
private:
    Type& v_;
};

こんな感じで,「ラッパクラスにラップ元の型へのキャスト演算子を定義しておく」と利便性が向上する場合も結構出てくるのではないかなと思います.

キャスト演算子オーバーロードも乱用されると非常に分かりづらいクラスが出来上がってしまうので使いどころは難しいですが,うまく使っていければなと思います.

広告を非表示にする