オレオレクラスによるシフト（ストリーム）演算子とコンマ（カンマ）演算子オーバーロードを利用したオレオレライブラリ

# 今までの流れ

+ ここ最近の最終目標は行列計算を使った組込制御
+ ところで「そのコンパイラなら`c++`が使えるかも」と通達された
    + えっ`class`と標準ライブラリ使っていいのか！？やったー
    + 本当に`c++`が通った，今まで誰もやってないだけだった…
+ ただし`c++98`標準にのみ対応，もしくは`c99`標準にのみ対応
    + かつCPUが特殊で一般的なコンパイラ（LLVM等）が使えない
    + アライメントの扱いが特殊なせいか`Eigen`が使えなかった
        + オブジェクト生成+リンクはおろかヘッダ導入すら無理
    + `vector`はいける感があるらしい，それでなんとかしたい
+ `Eigen`なし`-std=c++98`縛りで，似たようなものを実装する




# 今回やったこと
`c++`入門ついでにオブジェクト指向コーディング

+ まず，`c++`の基本
+ クラスの設計・実装
    + 名前空間
    + 相互参照
    + メンバ変数，メンバ関数
    + コンストラクタ，デストラクタ
        + コピーコンストラクタは扱わない
    + `protected`・`public`・`friend`
    + 自己参照
        + 実質的には再帰処理
+ 演算子のオーバーロード
    + シフト演算子
        + ある意味でストリーム的に活用
    + コンマ演算子
        + 区切りとしての意味合いを活用
+ `Eigen`もどきはまだ未完成なのでまた今度
    + こっちの演算子のオーバーロードは特殊
    + コピーコストと実用性の狭間で揺れ動く
    + もしかしたら公開できないかもしれない



## お題

+ `Eigen`は`matrix`を相手に`<<`を挟んで数字+カンマを含めた入力を扱うことができる
    + `M << 1,2,3;`
    + ストリームみたいだがストリームではない，たまたま`ios`クラスが`<<`と`>>`を使ってるだけ，これは`Eigen`に固有の実装らしい
+ これはとても便利なので，まずはその雛形を作る
    + 入力して出力できればOKです




# 以下，できたもの

```../MyIO/Catcher.hpp
#pragma once
#include <vector>
#include <Grabber.hpp>


namespace MyIO{

    class Grabber;
        //相互参照を設定する

    class Catcher{
        protected:
            std::vector<long double> arr;
                //データを保存する
        public:
            Catcher();
                //コンストラクタ
            ~Catcher();
                //デストラクタ
            Grabber operator<<(long double num);
            // データを"<<"で取る
            // Grabberを呼び出す
            void drainup();
                //溜めたデータを出す
        friend class Grabber;
            //Grabberとの連携を許可する
    };

};
```

```../MyIO/Grabber.hpp
#pragma once
#include <Catcher.hpp>


namespace MyIO{

    class Catcher;
        //相互参照を設定する

    class Grabber{
        protected:
            Catcher &catcherMem;
                //Catcherの参照を保存する
                //（データを返すのに使う）
        public:
            Grabber(Catcher &catcherRef):catcherMem(catcherRef){};
                //Catcherが呼び出せる初期化を定義する
                //Catcherの参照をメンバ変数に保存する
                //今回は明示的な初期化を行わないとダメ
            ~Grabber();
            Grabber& operator,(long double num);
                //データを","で取る
                //自身のポインタを返して再帰処理を行う
        friend class Catcher;
        //Catcherとの連携を許可する
    };

};
```


```../MyIO/Catcher.cpp
#include <iostream>
#include <Catcher.hpp>
#include <Grabber.hpp>


using namespace MyIO;

Catcher::Catcher(){
    std::cout << "Create Catcher" <<std::endl;
};

Catcher::~Catcher(){
    std::cout << "Delete Catcher" <<std::endl;
};

Grabber Catcher::operator<<(long double num){
    arr.assign(1,num);
        //長さ1で初期化して，その先頭にnumを代入する
    std::cout << "Create Grabber" <<std::endl;
    return (Grabber(*this));
        //自身の参照を渡してGrabberを起爆する
        //以降はGrabberが勝手に再起処理を行う
};

void Catcher::drainup(){
    for (size_t i = 0; i < arr.size(); i++){
            std::cout << arr[i] << " ";
    }
    std::cout << std::endl;
    arr.clear();
};
```

```../MyIO/Grabber.cpp
#include <iostream>
#include <Grabber.hpp>
#include <Catcher.hpp>


using namespace MyIO;

Grabber::~Grabber(){
    std::cout << "Delete Grabber" <<std::endl;
};

Grabber& Grabber::operator,(long double num){
    std::cout << "Altern Grabber" <<std::endl;
    catcherMem.arr.push_back(num);
        // 最後にnumを代入する
    return (*this);
        //自身の参照を渡してGrabberを起爆する
        //以降はGrabberが勝手に再起処理を行う
};
```

```makefile:makefile
NAME	=	test.exe
SRMN	=	main.cpp
SRSB	=	myIO/Catcher.cpp myIO/Grabber.cpp
INCL	=	myIO
OBMN	=	test.exe
OBSB	=	$(SRSB:%.cpp=%.out)
GCCC	=	clang++
GCOP	=	-std=c++98

make	:	$(SRMN) $(SRSB)
	$(GCCC) $(GCOP) $(SRMN) $(SRSB) -I $(INCL) -o $(OBMN)
```

```main.c
#include <Catcher.hpp>
#include <Grabber.hpp>


using namespace MyIO;

int main(){

    Catcher foo;

    foo << 1, 2, 3, 4, 5;
    foo.drainup();
    foo << 6, 7, 8, 9, 10;
    foo.drainup();
    long double bar = 1;
    foo << bar/1, bar/2, bar/3, bar/4, bar/5;
    foo.drainup();

};
```

実行結果

```zsh
% make      
clang++ -std=c++98 main.cpp myIO/Catcher.cpp myIO/Grabber.cpp -I myIO -o test.exe
% ./test.exe
Create Catcher
Create Grabber
Altern Grabber
Altern Grabber
Altern Grabber
Altern Grabber
Delete Grabber
1 2 3 4 5 
Create Grabber
Altern Grabber
Altern Grabber
Altern Grabber
Altern Grabber
Delete Grabber
6 7 8 9 10 
Create Grabber
Altern Grabber
Altern Grabber
Altern Grabber
Altern Grabber
Delete Grabber
1 0.5 0.333333 0.25 0.2 
Delete Catcher
```




# 解説



## アルゴリズム
要するに

```cpp
M;
M << fa,fb,fc;
```
に対して

1. 親クラス生成
1. 算術演算（`+`，`-`，`*`，`/`）の発生
    - いずれも`<<`と`,`より優先度が高い
1. `<<`演算，親クラス起爆+データ取る+親クラスの参照を持つ子クラス生成
1. `,`演算，子クラス起爆+データ取る（親クラス参照）+子クラス自己参照
1. `,`演算，子クラス起爆+データ取る（親クラス参照）+子クラス自己参照
1. （以下`;`が来るまで演算の再帰処理が発生，`;`が来れば勝手に終了）

を実装すればよい

![説明.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540440/3d696152-70a8-952e-ead9-8cb035b63614.png)

つまり

+ 2種類の演算子にオーバーロード
+ クラスに自己参照・相互参照のシステム

があればOKと言える



## 実行結果について
`Create`と`Delete`は`Catcher`と`Grabber`の生成と削除，`Altern`は`Grabber`の再起
`Catcer`は1回の生成と削除
`Grabber`は入力の度に生成と削除，および引数の分だけ再起



## 名前空間
ヘッダでもソースでも，ファイルが異なっても名前空間は共用できた，便利



## 相互参照と`protect`と`friend`の併用
クラス定義する前の相互参照の宣言と，`protect`に接続させる`friend`の宣言は，両方とも必要だった
`private`を選ばなかったのはクラス継承で弄りたくなった時に痛い目をみそうな予感がしてしまったから



## コンストラクタ・デストラクタ
ロギングによって追跡できるようにした，これに加えてコピーコンストラクタもあればコストが把握できる

```cpp
myClass::myClass(){}; //デフォルトコンストラクタ
myClass::myClass(class arg){}; //引数ありコンストラクタ
myClass::~myClass(){}; //デフォルトデストラクタ，引数はない
myClass::myClass(const myClass &myObject){};  //コピーコンストラクタ，引数は自クラスのオブジェクトの参照
```


### 明示的初期化

いまいちよくわからないが（日本語で検索しても引っ掛からなかった）多分

+ デフォルトコンストラクタが定義されていない
+ 自明なデフォルト値がないメンバ変数を抱える

クラスでは一発目の定義の時点でメンバ変数を初期化する必要があるらしい

```cpp
myClass::myClass(class arg):var(arg){}; //明示的初期化
```

今回は`Grabber`で引っかかりコンパイルエラーを吐かれたので修正した
なお，引数を加工するメンバ関数をコンストラクタに渡すのはアリらしい


```cpp
int myClass::fcn(class arg){return arg;}; //引数を加工できる関数を用意する
myClass::myClass(class arg):var(fcn(arg)){}; //それを使って初期化を工夫する
```



## ライブラリ設定
コンパイル時の命令で`-I $(PATH)`すれば良い，そうすると`<myHeader>`記法が使えて便利



## 演算子オーバーロード
以下は一例

```cpp
classReturn operator _operator_ (class1 arg1[,class2 arg2]){
    classReturn a = fcn(arg1[,arg2]);
    return a;
};
```

`_operator_`には使いたい演算子を設定する（ただし設定できないものもある）

演算子オーバーロードをクラス内の`public`なメンバ関数で定義しており，かつ左辺の変数のクラスが定義しているクラスと一致する場合は，引数に設定するのは右辺の変数のみで済む（その際`this`ポインタが左辺の変数を指すため）（下記のような書き方もできなくはないらしい）
右辺の変数に定義しているクラスの変数を使いたいような場合は，（右辺の変数，左辺の変数）の順で引数を2つ定義した上で，アクセスしたいメンバ変数やメンバ関数を`public`にするか，`protected`にした上で演算子オーバーロードに`friend`に設定する必要があるっぽいな？
要は`friend`でまとめて定義した方が管理が楽かも
しかし`()`だけはメンバ関数でやらないといけない
あと参照受けするとコピーコスト少ないんじゃないか
ちなみに三項演算子はオーバーロードできないらしい




# 感想
マジでなんもわからん状態からここまで持ってこれたのでインターネットの集合知に感謝してる
必要に迫られ次第で年末年始関係なくコーディングが楽しくなってくるってはっきりわかんだね



## 参考


https://qiita.com/h_hiro_/items/a6484101d87847299885

実際はこちらを再構成したものになりますが，解読と解釈を入れて個人的に読みやすくしました
@h_hiro_ さん，大変ありがとうございます，`-std==c++98`設定でもちゃんと動きました


https://qiita.com/tediousWerk/items/04e61864a20afb4ecee7

右辺に`this`ポインタがない事情について


https://brain.cc.kogakuin.ac.jp/~kanamaru/lecture/C++2/09/09-03.html

コピーコンストラクタについて


https://hakase0274.hatenablog.com/entry/2019/09/28/200000

明示的初期化について


http://wisdom.sakura.ne.jp/programming/cpp/cpp15.html

`this`ポインタについて


https://cpprefjp.github.io/reference/vector/vector.html

`<vector>`について


https://skpme.com/662/

`friend`について


https://pknight.hatenablog.com/entry/20090830/1251603528

`friend`と演算子オーバーロードのコンボについて


https://www.ibm.com/docs/ja/xl-c-and-cpp-aix/13.1.0?topic=only-variadic-templates-c11

可変数引数テンプレートというのもあったがそもそも`Eigen`のやり方が便利なので採用しなかった


https://kaworu.jpn.org/cpp/%E3%82%AA%E3%83%BC%E3%83%90%E3%83%BC%E3%83%AD%E3%83%BC%E3%83%89

オーバーロードの概要と事例


https://marycore.jp/prog/cpp/function-object/

`()`のオーバーロードは関数オブジェクトと呼称されるらしい


https://programming-place.net/ppp/contents/cpp/language/019.html

https://programming-place.net/ppp/contents/cpp/language/034.html

あとはここがとても詳しかったと思う