C++23 Deducing this | 備忘録

備忘録

C++/DirectX/Metal 等のネタを書いていきます。
あちこちで解説されてるような内容は基本書きません。
プログラミング以外のネタを書くこともありますが、消す可能性があります。
スマホ表示だとコードの部分がスクロール出来ないのでPC版表示でお願いします。

 どっかで見て「この提案、実装されて欲しいなぁ」と思ってたのが、C++23で採用されていたようです。

  P0847R7 Deducing this

 ちょっと面倒なのでサンプルコードは書かないけど(というか↑見て)、これがあれば非const版とconst版でほぼ同じコードのメンバ関数とかを、hoge(this T &self) とか書いてテンプレートにまとめられる。

 さらに、CRTPが、Curiously Recurring(不思議に再帰)する必要が無くなり、これまたthisをテンプレートにする(autoでもいける?)だけで書ける=メンバ関数テンプレートだけで良くなる。
 クラスのテンプレートパラメータが無くなるので、ポリモーフィズムを阻害しない。


 Xcodeのclangに来るのはまだ先だろうけど・・・・


<追記>
 まだ来てないので実用してないけど、ポリモーフィズムとは相性が悪そう。
struct base {
template <typename T>
void hoge(this T &Derived)
{
int a = Derived.a[0];
}
};

template <size_t N>
struct derived : base {

int a[N];
};

int main() {
// your code goes here
derived<1> D;
base &B = D;
B.hoge(); // error!!
D.hoge();

return 0;
}


<実行結果>
prog.cc:18:13: warning: unused variable 'a' [-Wunused-variable]
18 | int a = Derived.a[0];
| ^
prog.cc:18:25: error: no member named 'a' in 'base'
18 | int a = Derived.a[0];
| ~~~~~~~ ^
prog.cc:32:7: note: in instantiation of function template specialization 'base::hoge' requested here
32 | B.hoge();
| ^
1 warning and 1 error generated.

 結局のところテンプレートなので、参照やポインタがbaseであれば呼び出した際のテンプレート実引数もbaseになる。
 (ちなみに当然ながらテンプレートパラメータを size_t N、引数を derived<N> &にすることも出来るので、定数値Nが必要な場合は取得出来る)

 共通の機能を継承で取り込むだけのベースクラス(はなからその目的の設計。「Modern C++ Design」で言われるところのポリシークラス等)であれば問題にならないんだけど、baseの参照やポインタで扱う際には、CRTP的な目的のdeducing thisを使ったメンバ関数テンプレートは一切使えない。つまりポリモーフィズムを使うような場面とは排他的になる(コンパイル時にエラーが出るのはメリットなんだけど)。
 これは言い換えれば「動的多態 vs. 静的多態」なので相性が非常に悪い。両立する場面は滅多に無さそう。
 これに気付かなかったのはあまりに鈍かったなぁ・・・・。

 基本的にはCRTPが必要とされるような状況や非const/const版を実装するのが楽になるだけ、と考えておいた方がいいかも。