13
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[C++] コンマ演算子はオーバーロードできる、ということを知った

Posted at

きっかけ

そもそものきっかけは、C++における行列やベクトルを扱うライブラリ「Eigen」を使ったことであった。

Eigenでは、行列やベクトルの値を直接指定するために、次のようなコードが使えるのである。

// 各要素がfloat型である3次ベクトル
Vector3f v1;

// 3つの値を設定する
v1 << 1, 2, 3;

(参考:Eigen: Quick reference guide

これを見たとき、最初「コンマは処理を順に行うだけのはずだけど、どうやったら実現できているのだろうか」と気になったのである。で先程ふと「もしかして、コンマ演算子はオーバーロードできる?」と思い至って調べたらまさにその通りであったのである。

簡単なコード例

以下のような使い方ができるクラスValueListを考える。これは`int'の値を以下のように指定できるクラスである。

int main(void){
    ValueList foo;
    
    foo << 1, 2, 3, 5, 8, 13, 21;
    
    // 値を順に出力
    foo.foreach([](int val){
        std::cout << val << std::endl;
    });
}

これを実現するためには、方針としては

  • ValueList << valueという演算の結果は、「後ろに, value」を続けられる型(仮にCommaInputとする)でなければならない
  • そのCommaInputもまた、「後ろに, value」を続けられる型でなければならない

ということになる。

まずValueList<<をオペレーターオーバーロードし、CommaInput型を生成するようにしている。

class ValueList{
    std::vector<int> values_;
    
public:
    ValueList(){}
    
    CommaInput operator <<(int value){
        // values_の中をvalue一つだけにする
        values_.assign(1, value);
        
        // その後にコンマ区切りで値が渡せるよう、そのためのクラスを返す
        return(CommaInput(*this));
    }
    
    template <class LambdaType>
    void foreach(const LambdaType & lambda){
        for(std::vector<int>::iterator it = values_.begin(); it != values_.end(); ++it){
            lambda(*it);
        }
    }
};

次いでCommaInput。これにValueListへの参照を保持しておき、カンマ区切りで値が与えられたら実際に値の追加を行う。

class CommaInput{
    ValueList & vl_;

public:
    CommaInput(ValueList & vl) : vl_(vl) {}

    // オペレーターオーバーロード
    // valueを実際にリストに追加し
    // また続けてカンマ区切りで値を指定できるように自身を返す
    CommaInput & operator ,(int value){
        vl_.values_.push_back(value);
        return *this;
    }
};

ソースコード全体はこちら。(動かすには、C++11のラムダ式に対応したコンパイラが必要です) https://gist.github.com/maraigue/d7b3029b88b28f6c090d

参考記事

  • C++ tips 3 カンマ演算子編
    • コンマ演算子のよい使い方についての解説だが、最後にコンマ演算子をオーバーロードする話が出ている。「初期化リストの代わりになるような類いのもの実装可能」とする一方、「見た目からはオーバーロードされていることが予測し辛い為、容易くメンテナンス性の悪いコードになってしまいますので、乱用は厳禁です」とも述べている。
  • GESブログ C++でパラメータ配列を実装する
    • 可変長引数に近いものを実装するために、コンマ演算子のオーバーロードを利用する例。
  • c++ - When to Overload the Comma Operator? - Stack Overflow
    • コンマ演算子をオーバーロードすることが有効な例など。
13
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?