Menu
Coddy logo textTech

テンプレートの特殊化

CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 66/104。

場合によっては、generic templateがすべての型でうまく機能するとは限りません。たとえば、Cスタイルの文字列を>で比較すると、実際のテキストではなくポインターアドレスが比較されます。template specializationを使うと、その他すべての型にはgeneric versionを維持しながら、特定の型に対してカスタムのimplementationを提供できます。

full 特殊化は、特定の1つの型に対してテンプレート全体を置き換えます。空のテンプレートパラメーターリストで宣言し、具体的な型を指定します。

// プライマリテンプレート
template <typename T>
class Printer {
public:
    void print(T value) {
        std::cout << value << std::endl;
    }
};

// const char* の完全特殊化
template <>
class Printer<const char*> {
public:
    void print(const char* value) {
        std::cout << "String: " << value << std::endl;
    }
};

Printer<int> intPrinter;
intPrinter.print(42);           // 出力: 42

Printer<const char*> strPrinter;
strPrinter.print("hello");      // 出力: String: hello

Functionテンプレートは特殊化することもできます。

template <typename T>
bool isEqual(T a, T b) {
    return a == b;
}

template <>
bool isEqual<const char*>(const char* a, const char* b) {
    return std::strcmp(a, b) == 0;
}

isEqual(5, 5);              // 汎用版を使用
isEqual("hi", "hi");        // 特殊化版を使用

コンパイラは常に最も具体的に一致するものを優先します。使用されている正確な型に対する特殊化が存在する場合は、汎用テンプレートよりもそちらが選択されます。

challenge icon

チャレンジ

簡単

特定の型に対して動作をカスタマイズしながら、それ以外のすべての型には汎用的なフォールバックを維持できる、テンプレート特殊化の仕組みを示す型対応フォーマッターシステムを構築しましょう。

テンプレートコードを整理するために、2つのファイルを作成します。

  • Formatter.h:値を表示用にフォーマットする、FormatterというクラステンプレートをDefineします。genericテンプレートは任意の型で動作するようにしますが、カスタム処理が必要な型については特殊化したバージョンも作成します。

    Primary Formatterテンプレートには、次のものを含めます。

    • 型Tの値を受け取り、Value: <value>とprintsするformat() method

    1または0ではなく、人間が読みやすいテキストをprintsするboolのFull特殊化を作成します。

    • format() methodは、Boolean: trueまたはBoolean: falseをprintsします。

    文字列を引用符で囲むconst char*のFull特殊化を作成します。

    • format() methodは、String: "<value>"をprintsします。

    同じ型の2つの値を受け取り、Pair: [<first>, <second>]としてまとめてprintsする、formatPairというfunctionテンプレートも作成します。

    各文字列を引用符で囲むconst char*用のformatPairの特殊化を作成します:Pair: ["<first>", "<second>"]

  • main.cpp:4つのinputsを読み取ります(それぞれ別の行に入力します)。
    1. integer
    2. double
    3. 文字列としてのboolean(trueまたはfalse
    4. 文字列の値

    適切なFormatterオブジェクトを作成し、それぞれの型に対してformat()をCallして、フォーマッターの動作を確認します。

    1. Formatter<int>を使用してintegerをフォーマットする
    2. Formatter<double>を使用してdoubleをフォーマットする
    3. Formatter<bool>を使用してbooleanをフォーマットする(最初に文字列の入力をboolにConvertする)
    4. Formatter<const char*>を使用して文字列をフォーマットする

    次に、functionテンプレートの特殊化を確認します。

    1. 2つのintegers(10と20)を指定してformatPairをCallする
    2. 2つのC-strings("hello""world")を指定してformatPairをCallする

たとえば、inputsが423.14trueHelloの場合:

Value: 42
Value: 3.14
Boolean: true
String: "Hello"
Pair: [10, 20]
Pair: ["hello", "world"]

genericテンプレートはintegersとdoublesを同じように処理する一方、boolconst char*の特殊化されたバージョンはカスタムフォーマットを提供していることに注目してください。コンパイラーは、使用する各型に対して最もspecificな一致を自動的に選択します。

自分で試してみよう

#include <iostream>
#include <string>
#include "Formatter.h"

using namespace std;

int main() {
    // 入力を読み取る
    int intVal;
    double doubleVal;
    string boolStr;
    string strVal;
    
    cin >> intVal;
    cin >> doubleVal;
    cin >> boolStr;
    cin >> strVal;
    
    // 文字列をboolに変換する
    bool boolVal = (boolStr == "true");
    
    // TODO: Formatter<int>を作成して整数をフォーマットする
    
    // TODO: Formatter<double>を作成してdoubleをフォーマットする
    
    // TODO: Formatter<bool>を作成してbooleanをフォーマットする
    
    // TODO: Formatter<const char*>を作成して文字列をフォーマットする
    // ヒント: strVal.c_str()を使ってconst char*を取得する
    
    // TODO: 2つの整数10と20でformatPairを呼び出す
    
    // TODO: 2つのC文字列"hello"と"world"でformatPairを呼び出す
    
    return 0;
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: C++オンラインコンパイラ