テンプレートの基本概念
テンプレートはクラスや関数の設計図であり、コンパイル時に特定の型に基づいて具体的なコードが生成される。このプロセスをインスタンス化と呼ぶ。
関数テンプレートの定義
// 型パラメータTを持つ関数テンプレート
template<typename T>
int compare_values(const T& lhs, const T& rhs) {
if (lhs < rhs) return -1;
if (rhs < lhs) return 1;
return 0;
}
非型テンプレートパラメータ
// 文字列リテラルの長さをテンプレートパラメータとして受け取る
template<size_t N, size_t M>
int compare_strings(const char (&s1)[N], const char (&s2)[M]) {
return std::strcmp(s1, s2);
}
// 使用例: 配列サイズが自動的に推論される
compare_strings("hello", "world"); // N=6, M=6(ヌル終端含む)
クラステンプレートの実装
template<typename T>
class Container {
public:
using value_type = T;
using size_type = typename std::vector<T>::size_type;
Container() : data(std::make_shared<std::vector<T>>()) {}
Container(std::initializer_list<T> init)
: data(std::make_shared<std::vector<T>>(init)) {}
void add(const T& item) { data->push_back(item); }
T& get(size_type idx) {
if (idx >= data->size())
throw std::out_of_range("Index out of bounds");
return (*data)[idx];
}
private:
std::shared_ptr<std::vector<T>> data;
};
クラステンプレートのメンバ関数定義
template<typename T>
T& Container<T>::get(typename Container<T>::size_type idx) {
// 実装内容...
}
テンプレート型エイリアス
// ペア型のエイリアス
template<typename T>
using Pair = std::pair<T, T>;
Pair<std::string> authors; // std::pair<std::string, std::string>
// 部分固定パラメータ
template<typename T>
using IdPair = std::pair<T, unsigned int>;
IdPair<Product> product_entry; // std::pair<Product, unsigned int>
テンプレート引数の推論と制御
明示的テンプレート引数指定
template<typename ReturnType, typename T1, typename T2>
ReturnType calculate(T1 a, T2 b) {
return static_cast<ReturnType>(a + b);
}
// 使用例
auto result = calculate<long>(3, 4.5); // long型で結果を返す
右辺値参照とフォワーディング
// 完全転送を実現するヘルパー関数
template<typename T>
typename std::remove_reference<T>::type&& move_value(T&& arg) {
return static_cast<typename std::remove_reference<T>::type&&>(arg);
}
// 可変引数テンプレートでの転送
template<typename Func, typename... Args>
void execute(Func&& f, Args&&... args) {
f(std::forward<Args>(args)...);
}
可変引数テンプレート
再帰的処理パターン
// 基本ケース:単一要素の処理
template<typename T>
void log_args(const T& value) {
std::cout << value << std::endl;
}
// 再帰ケース:先頭要素を処理後、残りを再帰呼び出し
template<typename T, typename... Rest>
void log_args(const T& first, const Rest&... rest) {
std::cout << first << ", ";
log_args(rest...);
}
// 使用例
log_args(1, "hello", 3.14); // 出力: 1, hello, 3.14
パラメータパックの展開
template<typename... Args>
void process_all(Args&&... args) {
// 各引数にdebug_info関数を適用
auto dummy = {(debug_info(std::forward<Args>(args)), 0)...};
(void)dummy; // 警告抑制
}
テンプレートの特殊化
関数テンプレートの完全特殊化
// 一般テンプレート
template<typename T>
int compare(const T& a, const T& b) { /* 一般実装 */ }
// 文字列ポインタ用の特殊化
template<>
int compare<const char*>(const char* const& a, const char* const& b) {
return std::strcmp(a, b);
}
クラステンプレートの部分特殊化
// 一般テンプレート
template<typename T>
struct TypeWrapper {
using type = T;
};
// ポインタ型用の部分特殊化
template<typename T>
struct TypeWrapper<T*> {
using type = T;
static constexpr bool is_pointer = true;
};
// 使用例
TypeWrapper<int*>::is_pointer; // true
標準ライブラリの特殊化例
namespace std {
template<>
struct hash<CustomType> {
size_t operator()(const CustomType& obj) const {
return hash<string>()(obj.id) ^
hash<int>()(obj.value);
}
};
}