Help us understand the problem. What is going on with this article?

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

More than 3 years have passed since last update.

きっかけ

そもそものきっかけは、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
    • コンマ演算子をオーバーロードすることが有効な例など。
h_hiro_
本業ではアルゴリズム作ったりしてます。プログラミングは業務経験はないですが趣味&本業の研究でいろいろ書いてます。
http://hhiro.net/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away