テンプレート#
イントロダクション#
テンプレートを使用すると、クラスまたは関数の操作を定義し、その操作が具体的にどの型で動作するかをユーザーが指定できるようになります。 なんのこっちゃって感じですね実際の例を見て確認していきます。
#include <iostream>
template <typename T>
T add(const T& a, const T& b)
{
const T c = a + b;
return c;
}
int main(int argc, const char * argv[]) {
std::cout << add<double>(0.2,0.3) << std::endl;
return 0;
}
typename キーワードは、このパラメーターが型のプレースホルダーであることを示します。 関数が呼び出されると、コンパイラは、T のすべてのインスタンスを、ユーザーによって指定されるか、コンパイラによって推測される具体的な型引数に置き換えます。
テンプレート制約#
例のadd
関数はどんな型でも受け取れてしまいます。では下記のような構造体を入れるとどうなるでしょう。
struct point3{
double x, y, z;
}
#include <iostream>
template <typename T, typename = void>
struct IsLikePoint3 : std::false_type {};
template <typename T>
struct IsLikePoint3<
T, std::void_t<
decltype(std::declval<T>().x),
decltype(std::declval<T>().y),
decltype(std::declval<T>().z)
>>
: std::true_type {};
template <
typename T,
std::enable_if_t<std::conjunction_v<std::is_scalar<T>>, std::nullptr_t> =
nullptr>
T add(const T& a, const T& b)
{
const T c = a + b;
return c;
}
template <
typename T,
std::enable_if_t<std::conjunction_v<IsLikePoint3<T>>, std::nullptr_t> =
nullptr>
T add(const T& a, const T& b)
{
auto c = T();
c.x = a.x + b.x;
c.y = a.y + b.y;
c.z = a.z + b.z;
return c;
}
struct point3{
double x, y, z;
};
int main(int argc, const char * argv[]) {
double x1 = 0.2;
double x2 = 0.4;
point3 p1 = {0.1,0.2,0.3};
point3 p2 = {0.3,0.2,0.1};
auto resultx = add(x1,x2);
auto resultp = add(p1,p2);
std::cout << resultx << std::endl;
std::cout << resultp.x << "," << resultp.y << "," << resultp.z << std::endl;
return 0;
}