モダンC++とCでの代替手法

C++のテンプレートとCの汎用プログラミング

このレッスンでは、C++のテンプレートでいろいろなデータ型に使える関数を書き、C11の_Genericと比べます。

はじめに

テンプレートを使うと汎用的なコードのひな形を書けて、コンパイラが型の安全性を保ったまま、データ型ごとに合ったバージョンを自動で作ります。Cでは、同じ目的のためにマクロ、voidポインタ、C11のキーワード_Genericなどを使うのが一般的です。

大切なポイント

  • C++の抽象化を学ぶ前に、Cでのやり方を理解しましょう。
  • RAIIと値のセマンティクス(value semantics)で、リソースの持ち主を表しましょう。
  • マクロや型変換より、C++の型安全な道具を優先しましょう。

CとC++のコード例

C
実行 →
main.c
#include <stdio.h>

int max_int(int left, int right) {
    return left > right ? left : right;
}

double max_double(double left, double right) {
    return left > right ? left : right;
}

#define MAX(left, right) _Generic((left), \
    int: max_int, double: max_double)((left), (right))

int main(void) {
    printf("%d %.1f\n", MAX(3, 9), MAX(2.5, 7.0));
}
実行結果
9 7.0
C++
実行 →
main.cpp
#include <iostream>

template<class T>
T maximum(const T& left, const T& right) {
    return left > right ? left : right;
}

int main() {
    std::cout << maximum(3, 9) << ' '
              << maximum(2.5, 7.0) << '\n';
}
実行結果
9 7

CとC++の比較

CのマクロMAXは_Genericで引数の型を見てmax_intかmax_doubleを選びますが、対応する型を1つずつ書き並べておく必要があります。C++のテンプレートmaximumは、型ごとに関数を書き直さなくても、比較>が使えるすべての型で動きます。

C

Cは名前付けの習慣、コールバック、マクロ、文脈を持つstructを使います。

C++

C++はスコープがはっきりした型安全な抽象化を用意しており、実行時のコストはふつうかかりません。

発展問題

両方のバージョンを実行し、コードを書き換えて、それぞれの言語がもたらす安全性の違いを観察しましょう。

  • まずCで仕組みを書き、その後で対応するC++の機能を使いましょう。
  • 手作業のリソース解放をRAIIに置き換えましょう。
  • その機能がメモリの確保や仮想関数の呼び出しを生むかどうかを確認しましょう。

チャレンジで練習する

このレッスンの内容を使って実際の問題を解きましょう。各チャレンジはブラウザで動き、すぐにテストされ、AI のレビューも受けられます。

すべてのチャレンジ