【一人 C++20 Advent Calendar 2019】C++ にコンセプトがやってくる!【25日目】
一人 C++20 Advent Calendar 2019 25日目の記事になります。
C++ にコンセプトがやってくる!
ついに C++ にコンセプトがやってきました!
C++11 の時代から長かった…。
コンセプトとはテンプレートパラメータに対して任意の制約を指定することができるようになる機能になります。
細かいところを話し出すと止まらないので簡単な例を記述すると以下のような使い方になります。
#include <string> #include <iostream> // T 型に対する制約を定義する template<typename T> concept printable = requires (T& t) { // T に対して任意のメンバ関数が呼べるかどうかの条件 t.name(); // 複数書くことで複数の制約を定義できる // また、以下のように書くことでメソッドの戻り値に対する制約も定義できる { t.sound() } -> std::string; }; // テンプレート引数を定義する時に typename や class の代わりに // concept で定義した制約名を記述できる // この場合は printable の条件の型のみをテンプレートで受け取ることになる template<printable T> void print(T const& obj) { std::cout << obj.name() << " : " << obj.sound() << std::endl; } // こちらは通常の関数テンプレートになる // printable の制約に当てはまらなかった場合にこちらを呼び出す template<typename T> void print(T const& obj) { std::cout << "出力できません" << std::endl; } struct cat { std::string name() const { return "ねこ"; } std::string sound() const { return "にゃーん"; } }; struct dog { std::string name() const { return "いぬ"; } std::string sound() const { return "わーん"; } }; struct X { int name() const { return 42; } int sound() const { return 42; } }; int main(){ // OK: printable の条件に当てはまってる print(cat{}); print(dog{}); // NG: printable の条件に当てはまらない print(X{}); return 0; } /* output: ねこ : にゃーん いぬ : わーん 出力できません */
C++ でメタプログラミングをやったことがある人なら必ず書いたことがあると思うんですが SFINAE を使ったテンプレート型の条件分岐ってめちゃくちゃむずかしいんですよね。
しかし、それがコンセプトを使うことで上のコードのようにめちゃくちゃすっきりと記述することができます。
そうそう、これだよこれ、これでいいんだよ。
もちろん上の使い方以外にも様々な用途でコンセプトを利用することができます。
詳しくは以下のまとめを読んでみてください。
いやー C++11 から長かったんですがやっとコンセプトが入りましたねえ…。
また、言語機能として追加されるだけではなくて標準ライブラリにもいくつか汎用的な制約が定義されています。
C++20 が楽しみですねー。
アドベントカレンダーを終えて
と、言うことで今日がクリスマス!そしてアドベントカレンダーが終わり!!!
勢いで始めたアドベントカレンダーだったんですがなんとか無事に完走することができました。
一つ一つの内容はとても薄っぺらいですが
始める前は C++20 って何が追加されるんじゃ???って感じだったんですが実際にどういう機能が追加されるのかを調べてみると細かい追加や修正がかなりされていることがわかりました。
特に「C++ で絶対に constexpr
するぞ!!!」という気持ちはめっちゃ伝わってきました。
まだ各コンパイラでは追加されてない機能やライブラリがあるので「ホンマに来年使えるようになるの???」みたいな気持ちがあるんですが、各コンパイラが対応されたらまた触ってみたいですねー。
それでは皆さん良いお年を。