メタ関数クラスとプレースホルダーと高階関数の違いは何ですか?
2 に答える
詳細な説明については、
原則として、メタ関数は次のいずれかです。
- すべてのパラメータが型であるクラス テンプレート
- 一般にアクセス可能な型のクラス
type
例えば:
template <bool, class L, class R>
struct IF
{
typedef R type;
};
template <class L, class R>
struct IF<true, L, R>
{
typedef L type;
};
別の関数を操作する関数は、高階関数と呼ばれます。したがって、高次メタ関数は、他のメタ関数をパラメーターとして受け入れ、計算中にそれらを使用するメタ関数です。これは概念的に、実行時に別の関数または関数オブジェクトへのポインターをパラメーターとして受け入れる関数に似ています。唯一の違いは、メタ関数がコンパイル時にのみ存在することです。boost::mpl::transform
は、そのような高次メタ関数の例です。
Boost は Metafunctions と高次関数の機能を提供しますが、その概念は Boost に固有のものではありません。
「メタ関数」という用語は、テンプレートの特殊化を使用して、コンパイラがテンプレート引数に応じてコンパイル時に決定を下せるようにするためのテンプレート メタプログラミング手法を表します。
通常、メタ関数は次のようになります
template<bool B>
struct my_metafunction
{
enum { value = 1 };
};
template<>
struct my_metafunction<false>
{
enum { value = 0 };
};
を使用するmy_metafunction
と、 の正確な値はBmy_metafunction<B>::value
の値に依存します(つまり、とは異なります)。テンプレートのメタプログラミングに慣れていない場合は、なぜこれが役立つのか疑問に思われるでしょう。実際には、テンプレートとコンパイル時の意思決定を多用するライブラリを作成する人にのみ役立つのが一般的です。(テンプレートのメタプログラミングはまったく異なるパラダイムです!)my_metafunction<true>::value
my_metafunction<false>::value
一方、「高階関数」は、関数を関数の引数として渡すことができる関数型プログラミング手法を表します。<algorithm>
これは、標準コンテナで動作する標準ライブラリを使用して、標準 C++ で表現する方が少し簡単です。
たとえば、C++ には と呼ばれる高階関数が含まれています。transform
その目的は、コンテナー内の各要素 (ベクター、文字列、リスト、マップ、配列など) をステップ実行し、各要素の変換を実行することです。
std::string str = "Hello, World";
std::transform(str.begin(),
str.end(),
str.begin(),
std::toupper); // Note - toupper is a function!
std::cout << str << std::endl;
実行される変換は、最終パラメータ に依存しますstd::toupper
。std::toupper の目的は、(文字) 値を受け入れ、その値の大文字バージョンを返すことです。str.begin()
std::transform は、 andの間の各要素の toupperstr.end()
の結果を取得します (この例では、結果は str に戻されます)
std::find_if
標準ライブラリにはstd::sort
、他にも高階関数の例がたくさんありますstd::count_if
。C++ の高階関数は通常、関数、ラムダ、関数オブジェクトなど、あらゆる種類の呼び出し可能なオブジェクトを受け入れることができます。
渡される呼び出し可能なオブジェクトは、しばしば [i]述語[/i] と呼ばれます (ただし、それが「述語」という用語の正しい使用法であるかどうかは完全にはわかりません)。
Boost プレースホルダーは、カリー化として知られる関数型プログラミングの別の側面の一部です。これにより、関数が呼び出される前にパラメーターを関数に「バインド」できます。(Boost の世界では、カリー化の結果は通常、高階関数に渡される関数オブジェクトです)。
カリー化は、既存の呼び出し可能オブジェクト/述語を再利用し、使用する前にそれらの引数の一部を具体的に設定することにより、独自のカスタムの特殊化された呼び出し可能オブジェクトを作成する代替手段として意図されています。
たとえば、higher-order-functionfind_if
を使用して、「q より大きい」最初の文字を文字列で検索できます。C++ 標準ライブラリには、と呼ばれる呼び出し可能なオブジェクトが含まれてgreater_equals
いますが、find_if で使用される 2 番目のパラメーターが必要です ("Greater than and equals ** to what??")。
カリー化せずに、次のような関数を書くことができます (今のところ、大文字と小文字の区別はすべて無視します)。
bool greater_than_or_equals_to_q(char c)
{
return c >= 'Q';
}
カリー化を使用すると、文字 'Q` を greater_equals 関数に「バインド」して、単一の引数のみを受け入れ、引数が「Q 以上」の場合に true を返す述語を表す述語を作成できます。
std::bind( std::greater_equal<char>(),
std::placeholders::_1,
'Q' );
したがって、大文字の文字列を使用すると、次のようになります。
std::string str = "HELLO WORLD";
auto gt_eq_Q = std::bind( std::greater_equal<char>(),
std::placeholders::_1,
'Q' );
auto iter = std::find_if( str.begin(), str.end(), gt_eq_Q );
std::cout << *iter << std::endl;
期待どおりの出力 - 「Q」以上の「HELLO WORLD」の最初の文字はたまたま「W」です
W