最終更新:2026-10-12
C++ 関数テンプレートよりクラステンプレート¶
最近、とても面白いテンプレートの問題を見かけました。関数テンプレートとクラステンプレートの基礎をどれだけ握っているか試される問題です。下の例では何が起こるでしょうか?
普通はどうやって直しますか?
template <typename T, int R>
struct foo {
foo(const T& v) : value_(v) {}
void bar() {
std::cout << "Generic" << std::endl;
for (int i = 0; i < R; ++i) std::cout << value_ << std::endl;
}
T value_;
};
template <>
void foo<float, 3>::bar() {
std::cout << "Float" << std::endl;
for (int i = 0; i < 3; ++i) std::cout << value_ << std::endl;
}
template <int R>
void foo<double, R>::bar() {
std::cout << "Double" << std::endl;
for (int i = 0; i < R; ++i) std::cout << value_ << std::endl;
}
答えは:最後の 2 つの特殊化はそのままコンパイルが通りません。
(1)1 つ目の template <> void foo<float, 3>::bar() は**完全特殊化**なので問題なし;
(2)2 つ目の template <int R> void foo<double, R>::bar() は**部分特殊化**をしようとしています——しかし関数テンプレートに部分特殊化は許されません! コンパイラはこれを新しい関数テンプレートのオーバーロードとして解析し、シグネチャが合わず、そのままエラーになります。
直し方は?クラステンプレートの登場¶
C++ のルールはこうです:関数テンプレートは完全特殊化しかできず、部分特殊化は不可能;クラステンプレートは両方可能。そこでイディオムとして、「型で分岐させたいロジック」を関数テンプレートから取り出してクラステンプレート(普通は trait/policy)に入れ、クラスに対して部分特殊化します:
template <typename T, int R>
struct bar_impl {
static void run(foo<T, R>& f) {
std::cout << "Generic" << std::endl;
for (int i = 0; i < R; ++i) std::cout << f.value_ << std::endl;
}
};
template <int R>
struct bar_impl<double, R> { // 类模板偏特化:合法!
static void run(foo<double, R>& f) {
std::cout << "Double" << std::endl;
for (int i = 0; i < R; ++i) std::cout << f.value_ << std::endl;
}
};
template <typename T, int R>
void foo<T, R>::bar() { bar_impl<T, R>::run(*this); }
これは STL の定番の手口でもあります:iterator_traits、__type_traits、どれも「クラステンプレートが部分特殊化を担う」路線です。
まとめ¶
(1)関数テンプレート:オーバーロード+完全特殊化のみ、部分特殊化は不可;
(2)「特定の系統の型に特殊な実装を与えたい」ときは、実装をクラステンプレートに移し、部分特殊化/trait で振り分ける;
(3)C++11 以降は if constexpr で関数本体の中で直接分岐できる場面も多く、クラステンプレートすら省けます——ただし部分特殊化とのトレードオフは、あなたの考えに委ねます。
関連トピック¶
- C++ デフォルトコンストラクタの回避 | C++那些事
- C++ クラス初期化リストイディオム | C++那些事
- C++ copy-and-swap イディオム | C++那些事
- C++ 依存性注入 | C++那些事
- C++ enum class 強い型付けされた列挙 | C++那些事
- C++ Header-Only と実装分離 | C++那些事
- C++ 遅延評価イディオム | C++那些事
- C++ ルックアップテーブル法イディオム | C++那些事
- C++ メンバポインタと型情報 | C++那些事
- C++ Mixin イディオム | C++那些事