メタ関数を用いた記述を取り入れたいと考えているのですが、使えそう、と思える場面に出会えません。
型を確かめたりメンバ関数を確かめたりせずともテンプレート、オーバーロードなどで不便がないことばかりです。SFINAE…?特殊化ではだめなの?と考えてしまいます。
間違いなく僕が理解していないだけなのですが、使い道・こんな時に使用する、というのを教えていただきたいです。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答2件
0
C++ Core Guidelinesにて、いくつか関連するガイドラインが上がっています。
Metaprogramming rule summary(T.120-123):
- T.120: Use template metaprogramming only when you really need to
- T.121: Use template metaprogramming primarily to emulate concepts
- T.122: Use templates (usually template aliases) to compute types at compile time
- T.123: Use constexpr functions to compute values at compile time
C++03→11→14→17→20と言語仕様が改訂されるにしたがって、「メタ関数を用いた記述」が必要になる場面は減りつつあると思います。たとえばコンパイル時の 値(value)の計算 であれば constexpr関数 を用いた方が可読性が高くなりますし、C++20からは コンセプト(Concepts) の導入によりメタ関数を用いたSFINAEなどの難解な実装テクニックも不要になっていくでしょう。
Metaprogramming rule summary(T.124-125):
- T.124: Prefer to use standard-library TMP facilities
- T.125: If you need to go beyond the standard-library TMP facilities, use an existing library
とはいえ、完全にメタ関数が不要になるわけではありません。同ガイドラインにあるように 型(type)の計算 においては極力C++標準ライブラリ提供のメタ関数を用いるべきでしょう。
投稿2020/02/28 04:07
総合スコア6191
0
ベストアンサー
ある機能を実装するということだけではなく、間違った使い方をさせないという用途があります。 規模が小さい内には自分が実装した部品をどのように使うべきなのかは充分に把握しているでしょうが、少し規模が大きくなるとすぐに把握できなくなります。 また、他人が使うことを想定した部品ならなおさらです。
たとえばこういったごく簡単なテンプレートがあったとします。
cpp
1#include <iostream> 2#include <type_traits> 3 4template<class T> 5T increment(T a) { 6 return a+1; 7} 8 9int main(void) { 10 std::cout << increment(2) << std::endl; 11}
ここで関数 increment
に渡す型 T
は少なくとも 1
との間で足し算が可能な値であるという仮定がありますが、うっかり間違った型の値を渡してしまったとしましょう。
cpp
1#include <iostream> 2#include <type_traits> 3 4template<class T> 5T increment(T a) { 6 return a+1; 7} 8 9class foo{}; 10 11int main(void) { 12 std::cout << increment(foo()) << std::endl; 13}
100 行を超える長大なエラーメッセージが出たと思います。
誤った型でテンプレートを展開した上で辻褄が合わない箇所を全てエラーとして提示するからです。 本当に間違っている箇所はどこなのかを把握するのは大変でしょう。
それではこの関数 increment
に渡す型 T
は整数型であるという制約を付けてみましょう。
cpp
1#include <iostream> 2#include <type_traits> 3 4template<class T> 5typename std::enable_if<std::is_integral<T>::value, T>::type increment(T a) { 6 return a+1; 7} 8 9class foo{}; 10 11int main(void) { 12 std::cout << increment(foo()) << std::endl; 13}
おそらく大抵のコンパイラではエラーメッセージは 10 行かそこらではないでしょうか。
こちらのエラーはテンプレートを展開せずに「あてはまる関数がない」という意味のエラーになります。
テンプレートが間違った展開をした上でエラーになるのと展開をさせないのとではエラーメッセージの読み取りやすさが違います。
これはメタプログラミングというか「型を確かめる」という部分の重要さですね。
投稿2020/02/28 01:54
総合スコア5444
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/02/28 03:59
2020/02/28 04:00
2020/02/28 04:06
2020/02/28 04:52 編集
2020/02/28 07:13
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/02/28 04:34
2020/02/28 05:03
2020/02/28 05:11 編集
2020/02/28 05:17 編集
2020/02/28 06:21