コンテナの種類は問わないが、要素の型は限定したい。
C++ で STL などによる任意のコンテナを引数に取る関数を実装する際、そのコンテナの種類は問わないものの、そのコンテナが持つ要素の型は限定したい、あるいは要素の型に応じて処理内容を切り替えたい、といったニーズがあると思います。
そのような場合、 C++11 であれば、 <type_traits> を利用します。
以下は、整数の型を要素に持つ任意のコンテナを受け取り、その全要素の合計を返す関数 calcSum()
の実装例です。
#include <iostream> #include <type_traits> #include <array> #include <set> extern void * enabler; template <typename cont_t, typename value_type = typename cont_t::value_type, typename std::enable_if<std::is_integral<typename cont_t::value_type>::value>::type *& = enabler> value_type calcSum(cont_t const& container) { value_type sum = 0; for (auto n : container) sum += n; return sum; } int main() { std::array<int, 5> primes = { 2, 3, 5, 7, 11 }; for (int i = 0; i < primes.size(); i++) std::cout << (i == 0 ? "" : " + ") << primes[i]; std::cout << " = " << calcSum(primes) << std::endl; // std::array<double, 5> floating_nums = { 1.414, 1.732, 2.236, 2.718, 3.142 }; // auto result = calcSum(floating_nums); // エラー: そんな関数無いよ std::multiset<short> nums = { 152, 24, 73, -15, 250, 3, 24 }; bool is_first = true; for (auto num : nums) { std::cout << (is_first ? "" : " + ") << num; is_first = false; } std::cout << " = " << calcSum(nums) << std::endl; return 0; }
実行結果は以下の通りです。
2 + 3 + 5 + 7 + 11 = 28 -15 + 3 + 24 + 24 + 73 + 152 + 250 = 511
Boost ライブラリを含む C++ 全般の話題を追い続けてきた人であれば当然ご存じの知識だと思います。ええ、そうです、今回は完全に自分用のメモです (汗。こういう書き方があること自体は認識していたのですが、いやー、やっぱり実際に使わないことには身につかないですね (^_^;A 。
基本的には、テンプレートの中で、制限したい通りの条件に適合する場合のみ true
になるような定数式を std::enable_if<
~ >
で括ってやり、そのクラスメンバである型 type
を typename
として評価する、というものです。この std::enable_if<foobar>::type
は、 foobar
が true
になる場合のみ (テンプレートの特殊化によって) 定義されるような仕組みになっていて、これが false
になってしまう (すなわち、あなたの指定したい条件に合致しない) 呼び出し方をしようとすると、単にオーバーロードできないケースとして無視されます。
上記のケースでは要素が整数型以外の場合はオーバーロード可能な関数が存在しないものとしてコンパイルエラーになりますが、別途浮動小数点用の実装や std::complex<T>
用の実装、さらには std::string
用の実装なんかも用意してあげることで、それぞれに独自の処理を実現させるということもできちゃう、という寸法です。便利。
2012 年 9 月 27 日 by 村山 俊之