テンプレート(C++)
用途 : 型の違いに対応する
ファイル分割した場合、ヘッダーで定義する
テンプレート関数
用途 : 引数の型や戻り値の型の違いに対応する
example.cpp
#include <iostream>
#include <string>
#include <format>
template <typename T>
T Add(T n, T m)
{
return n + m;
}
int main()
{
// intやfloat、stringなど何でも対応可能
// 文字列型は種類が多いので、明示的に記述する
std::cout << std::format("10 + 20 は{}", Add(10, 20)) << std::endl;
std::cout << std::format("4.5 + 1.3 は{}", Add(4.5f, 1.3f)) << std::endl;
std::cout << std::format("Hello + World は{}", Add<std::string>("Hello", "World")) << std::endl;
return 0;
}
テンプレート関数の特殊化(オーバーロードみたいなもの)
example.cpp
#include <iostream>
#include <string>
#include <format>
// ベース
template <typename T>
T Add(T n, T m)
{
return n + m;
}
// 特殊化(ポインタ引数だった場合)
template <typename T>
T Add(T* n, T* m)
{
return *n + *m;
}
// 特殊化(引数の型が違う場合)
template <typename T, typename U>
std::string Add(T n, U m)
{
return "型が違うエラー!";
}
// 完全特殊化(排他的論理和)
template <>
bool Add<bool>(bool n, bool m)
{
if (n && m) return false;
else return true;
}
int main()
{
// 宣言・定義
int n = 10,
m = 20;
// 出力
std::cout << std::format("10 + 20 は{}",Add(n, m)) << std::endl;
std::cout << std::format("nとmのアドレスの値(10 + 20) は{}", Add(&n, &m)) << std::endl;
std::cout << std::format("n(アドレス) + m(int型)は{}", Add(&n, m)) << std::endl;
std::cout << std::format("true + true は{}", Add(n > 0, m > 0)) << std::endl;
return 0;
}
クラステンプレート
クラステンプレートとは、テンプレート仮引数型の変数や、テンプレート関数を持つクラス
Status.h
#ifndef STATUS_H_INCLUDED
#define STATUS_H_INCLUDED
#include <iostream>
template <typename T>
class Status
{
public:
Status(const T _hp, const T _attack, const T _defense)
{
hp = _hp;
attack = _attack;
defense = _defense;
}
virtual ~Status() {}
inline T GetHp(void) { return hp; }
inline T GetAttack(void) { return attack; }
inline T GetDefense(void) { return defense; }
private:
T hp;
T attack;
T defense;
};
#endif // !STATUS_H_INCLUDED
example.cpp
#include "Status.h"
#include <format>
int main()
{
// インスタンスの生成
Status status(30, 20, 10);
// 出力
std::cout << std::format("体力 : {}", status.GetHp()) << std::endl;
std::cout << std::format("攻撃力 : {}", status.GetAttack()) << std::endl;
std::cout << std::format("防御力 : {}", status.GetDefense()) << std::endl;
return 0;
}
- 明確化
Status.h : template < typename T = int >
example.cpp : Status status(30, 20, 10);
でより明示的にできる
テンプレートクラスの継承
Character.h
#ifndef CHARACTER_H_INCLUDED
#define CHARACTER_H_INCLUDED
#include "Status.h"
#include <string>
// クラステンプレート(基底)
template <typename T>
class Character
{
public:
Character(const std::string _name, Status<T>* _status)
{
name = _name;
status = _status;
}
virtual ~Character() { delete status; }
inline Status<T>* GetStatus(void) { return status; }
private:
std::string name;
Status<T>* status;
};
// クラステンプレート
template <typename T>
class Dragon
: public Character<T>
{
public:
Dragon(Status<T>* status)
: Character<T>("ドラゴン", status)
{}
};
#endif // !CHARACTER_H_INCLUDED
#include "Character.h"
#include <format>
int main()
{
// クラステンプレートの派生クラスをアップキャストして動的確保
Character<int>* dragon = new Dragon(new Status(30, 20, 10));
// 出力
std::cout << std::format("体力 : {}", dragon->GetStatus()->GetHp()) << std::endl;
std::cout << std::format("攻撃力 : {}", dragon->GetStatus()->GetAttack()) << std::endl;
std::cout << std::format("防御力 : {}", dragon->GetStatus()->GetDefense()) << std::endl;
// 解放
delete dragon;
return 0;
}
クラステンプレート(オーバーロードみたいなもの)
用途 : 型の違いによって特化した処理を呼び出せる
// 特殊化
template <>
class Status<float>
{
public:
Status(const float _attackMultiplier, const float _defenseMultiplier)
{
attackMultiplier = _attackMultiplier;
defenseMultiplier = _defenseMultiplier;
}
virtual ~Status() {}
inline float GetAttackMultiplier(void) { return attackMultiplier; }
inline float GetDefenseMultiplier(void) { return defenseMultiplier; }
private:
float attackMultiplier; // 攻撃倍率
float defenseMultiplier; // 防御倍率
}
標準ライブラリではこういうのが使われていると思うだけでいいです。
C++の標準ライブラリを開発するような人以外は使いません(笑)
ジェネリック(C#)
ほぼ、C++のtemplateと同じです
違いといえば、型引数だけになるだけと
思ってもらえれば。
example.cs
using System;
public class Status<T>
{
private T hp;
private T attack;
private T defense;
public Status(T _hp, T _attack, T _defense)
{
hp = _hp;
attack = _attack;
defense = _defense;
}
public T GetHp() { get { return hp; } }
public T GetAttack() { get { return attack; } }
public T GetDefense() { get { return defense; } }
};
static int Main(string[] args)
{
Status<int> status = new Status<int>(30, 20, 10);
Console.WriteLine($"体力 : { status.GetHp() }\n");
Console.WriteLine($"攻撃力 : { status.GetAttack() }\n");
Console.WriteLine($"防御力 : { status.GetDefense() }\n");
}