**型消去(Type Erasure)の導出**

- **目的**  
  - 実行時に型パラメータを除去してジェネリックコードを単純化する。  
  - ジェネリックとレガシー(非ジェネリック)コードの相互運用性を実現する。

- **仕組み**  
  1. 各型パラメータをその *上限*(境界)が無ければ `Object` に置き換える。  
  2. バイトコードからジェネリック署名を消去する。  
  3. 必要に応じて多相性を保つためブリッジメソッドを生成する。

- **結果**  
  - 実行時にコンパイル時の型安全が失われる。  
  - 消えた型に依存する操作はキャストが必要になる。  
  - 不正なキャストが起これば `ClassCastException` が発生し得る。

- **実務上のヒント**  
  - 型消去の影響を抑えるため、可能なら境界付きワイルドカード(`<? extends T>`・`<? super T>`)を使用する。  
  - ジェネリックロジックは別途ヘルパークラスに分離しておくとよい。  
  - キャストロジックをカプセル化した型安全ビルダーやファクトリーを利用する。

2026/03/10 19:41

**型消去(Type Erasure)の導出** - **目的** - 実行時に型パラメータを除去してジェネリックコードを単純化する。 - ジェネリックとレガシー(非ジェネリック)コードの相互運用性を実現する。 - **仕組み** 1. 各型パラメータをその *上限*(境界)が無ければ `Object` に置き換える。 2. バイトコードからジェネリック署名を消去する。 3. 必要に応じて多相性を保つためブリッジメソッドを生成する。 - **結果** - 実行時にコンパイル時の型安全が失われる。 - 消えた型に依存する操作はキャストが必要になる。 - 不正なキャストが起これば `ClassCastException` が発生し得る。 - **実務上のヒント** - 型消去の影響を抑えるため、可能なら境界付きワイルドカード(`<? extends T>`・`<? super T>`)を使用する。 - ジェネリックロジックは別途ヘルパークラスに分離しておくとよい。 - キャストロジックをカプセル化した型安全ビルダーやファクトリーを利用する。

RSS: https://news.ycombinator.com/rss

要約

日本語訳:

(すべての重要ポイントを統合して明確に):**


要約

この記事では、

std::any
型消去 を実装し、具体的な型を一貫したインターフェースの背後に隠す方法について説明しています。これを他の二つの多態性スタイルと比較します。

  1. 従来の継承による多態性 – 仮想メソッドを持つ共通ベースクラス(
    Shape
    )を使用し、実行時に動作するが明示的なボイラープレートが必要で、階層が深くなる可能性があります。
  2. テンプレートベースの多態性 – コンパイル時に解決され、仮想呼び出しを排除しますが、各型ごとに別々のテンプレートインスタンス化が必要で、コンパイル時間とバイナリサイズが増大します。単一の実行時ベースクラスが存在しないためです。

互いに関連のない型(

Square
Circle
)を変更せずに共通インターフェース経由で使用できるようにするため、記事では
Shape
を継承したラッパークラスが保持オブジェクトへの呼び出しを転送する方法を示しています。ボイラープレートのラッパーは、テンプレート化された
ShapeWrapper<T>
を導入して回避され、コンパイル時に転送ロジックが生成されます。

型消去の核心は

AnyShape
実装で示され、各ラップされた図形をヒープ確保モデル(
Model<T>
)として保存します。実際のコードでは、小さなオブジェクトをインラインに格納してヒープ割り当てを減らす小バッファ最適化(SBO)がよく追加されます。記事はまた、標準レイアウトと同様の汎用
Any
クラスをスケッチし、
Concept
ベース、テンプレート化された
Model<T>
、および
f()
などのメンバ関数の転送を示しています。

このパターンは他の STL の例(例:

std::function
)と比較され、C++20 の概念とは実行時抽象化ではなくコンパイル時チェックを行うものとして明確に区別されています。記事の最後には Rust における型消去についての議論への参照が付けられています。

結論:
型消去(

std::any
スタイルのラッパー)を使用することで、開発者は継承階層の冗長性やテンプレート多態性のコンパイル時コストを回避しつつ、異種型を受け入れる簡潔で柔軟な API を書くことができます。これにより、実行時多態性が必要なライブラリ作者とアプリケーションに恩恵があります。

本文

2026年3月10日

std::any
を見たことがありますか? その背後で何が起きているのか、気になったことはありませんでしたか?
恐ろしいように見えるインターフェースの裏側には 型消去 (type erasure) と呼ばれる古典的な手法があります。具体的な型を小さく統一されたラッパーで隠すことで、実装は隠蔽されます。仮想関数やテンプレートといった馴染みのあるツールから始めて、最小限の
std::any
を構築してみましょう。最後には、型消去が内部でどのように機能するかを明確に理解できるはずです。


インターフェースによる多態性

多態性を実現する典型的な方法は、呼び出したい純粋仮想メソッドからなるインターフェースを定義し、各実装ごとにその基底クラスを継承してメソッドを実装することです。

例えば、

area()
メソッドを持つ図形クラスを実装してみましょう。

// インターフェース
class Shape {
public:
    virtual ~Shape() = default;
    virtual auto area() const noexcept -> double = 0;
};

// 実 concrete クラス
class Square : public Shape {
    int side_;
public:
    explicit Square(int side) noexcept : side_{side} {}
    auto area() const noexcept -> double override { return side_ * side_; }
};

class Circle : public Shape {
    int radius_;
public:
    explicit Circle(int radius) noexcept : radius_{radius} {}
    auto area() const noexcept -> double override {
        return std::numbers::pi * radius_ * radius_;
    }
};

これらの実装をインターフェースに対して汎用的に使えるようにすれば、次のように書けます。

auto printArea(const Shape& shape) -> void {
    std::println("Area is {:.2f}", shape.area());
}

テンプレートによる多態性

継承は具体的な型が共通の基底クラスを持つときにうまく機能します。
しかし、例えば

std::string
や組み込み型(
int
など)では変更できません。このような場合でも同じインターフェースを提供していれば、テンプレートを使って代替できます。

auto printArea(const auto& shape) -> void {
    std::println("Area is {:.2f}", shape.area());
}

これは

area()
を引数なしで呼び出せて
double
を返す任意の型に対して機能します。
ただし、テンプレートには主に次の二つの欠点があります。

  1. 共有ランタイム基底がない – 各インスタンス化は別個なので、

    Square
    Circle
    を同じコンテナに混在させることができません。

    auto shapes = std::vector< ??? >{ &square, &circle };
    
  2. テンプレートの増殖 – 呼び出し側もテンプレートである必要があり、コンパイル時間が長くなりバイナリサイズが大きくなる可能性があります。


std::any
の導入

Square
Circle
が固定された型で共通の基底クラスを持たず、変更できないと仮定します。依然として単一の共通インターフェースで扱いたい場合、ラッパーを導入する方法があります。

class SquareWrapper : public Shape {
    Square square_;
public:
    explicit SquareWrapper(Square square) noexcept : square_{std::move(square)} {}
    auto area() const noexcept -> double override { return square_.area(); }
};

class CircleWrapper : public Shape {
    Circle circle_;
public:
    explicit CircleWrapper(Circle circle) noexcept : circle_{std::move(circle)} {}
    auto area() const noexcept -> double override { return circle_.area(); }
};

こうすれば

Shape
のインスタンスを直接扱えます。

auto printAreas(const std::vector<std::unique_ptr<Shape>>& shapes) -> void {
    for (const auto& shape : shapes)
        std::println("Area is {:.2f}", shape->area());
}

int main() -> int {
    std::vector<std::unique_ptr<Shape>> shapes;
    shapes.emplace_back(std::make_unique<SquareWrapper>(Square{2}));
    shapes.emplace_back(std::make_unique<CircleWrapper>(Circle{1}));
    printAreas(shapes);
}

この手法は動作しますが、明らかな欠点があります:各具体型ごとに別々のラッパー型を用意する必要があります。テンプレートを使えば多くの作業を簡略化できます。

template <typename T>
class ShapeWrapper : public Shape {
    T shape_;
public:
    explicit ShapeWrapper(T shape) noexcept : shape_{std::move(shape)} {}
    auto area() const noexcept -> double override { return shape_.area(); }
};

「型消去」イディオム

残るのは、上記の仕組みをさらに一つのクラスに隠すことで、呼び出し側がカスタムインターフェースやテンプレートに対処する必要がなくなることです。典型的な実装(常にヒープ割り当て)は次のようになります。

class AnyShape {
    // インターフェース
    class Shape {
    public:
        virtual ~Shape() = default;
        virtual auto area() const noexcept -> double = 0;
    };

    // ラッパー
    template <typename T>
    class ShapeWrapper : public Shape {
        T shape_;
    public:
        explicit ShapeWrapper(T shape) noexcept : shape_{std::move(shape)} {}
        auto area() const noexcept -> double override { return shape_.area(); }
    };

    std::unique_ptr<Shape> shape_;

public:
    template <typename T>
    explicit AnyShape(T&& shape)
        : shape_{std::make_unique<ShapeWrapper<T>>(std::forward<T>(shape))} {}

    auto area() const noexcept -> double { return shape_->area(); }
};

使用例は以前と同じです。

auto printAreas(const std::vector<AnyShape>& shapes) -> void {
    for (const auto& shape : shapes)
        std::println("Area is {:.2f}", shape.area());
}

int main() -> int {
    std::vector<AnyShape> shapes;
    shapes.emplace_back(Square{2});
    shapes.emplace_back(Circle{1});
    printAreas(shapes);
}

汎用的な
std::any

Concept
Model
は標準名です:前者は 型消去コンセプト(OO スタイルのインターフェースで、C++20 の concept とは無関係)を指し、後者はそのインターフェースを実装するテンプレートラッパー(モデル)です。

以下は

std::any
を模した最小限の
Any
クラスです。

#include <memory>

class Any {
    // インターフェース
    class Concept {
    public:
        virtual ~Concept() = default;
        virtual auto f() const noexcept -> double = 0;
    };

    // モデル
    template <typename T>
    class Model : public Concept {
        T obj_;
    public:
        explicit Model(T obj) noexcept : obj_{std::move(obj)} {}
        auto f() const noexcept -> double override { return obj_.f(); }
    };

    std::unique_ptr<Concept> obj_;

public:
    template <typename T>
    explicit Any(T&& obj)
        : obj_{std::make_unique<Model<T>>(std::forward<T>(obj))} {}

    auto f() const noexcept -> double { return obj_->f(); }
};

これで完了です!

Any
クラスは
std::any
の簡略版であり、型消去の核となるアイデアを示しています。実際には STL でも同様の手法が使われています(例:
std::function
)。

David Álvarez Rosa

同じ日のほかのニュース

一覧に戻る →

2026/03/15 7:10

**アゲルス・リナックス ― 時代を超えて使えるソフトウェア** このソフトウェアは、年齢や経験に関係なく「時代を越えた使いやすさ」と柔軟性を重視するユーザー向けに設計されています。

## Japanese Translation: --- ## Summary Ageless Linux は意図的にカリフォルニア州の AB 1043 年齢確認法を拒否し、監視への抗議として Debian ベースのディストリビューションを位置付けつつ、オペレーティングシステムプロバイダーであり続けます。プロジェクトは標準の `/etc/os-release` ファイルを Bash スクリプト経由で「Ageless Linux」に置き換え、通常モードでも **“flagrant” モード** でも年齢確認 API を提供しません。「flagrant」 モードでは `/etc/ageless/REFUSAL` ファイルをインストールし、§ 1798.501(a)(1)–(a)(2) に対する完全かつ意図的な非準拠を明示的に宣言し、執行措置を促します。 ウェブサイトには子供、学校、図書館、および USB ドライブや Raspberry Pi Pico デバイスを通じて OS を配布するための **詳細なガイダンス** が含まれており、これらはすべて AB 1043 の下でオペレーティングシステムプロバイダー活動に該当します。また、ディストリビューションが年齢データを収集しないため「影響を受ける子供」を特定できず、影響を受ける子供ごとの罰金を算出できないことも説明しています。 Ageless Linux は暗号的に不可能であることとプライバシー懸念を理由に年齢確認を決して実装しないと主張し、Apple、Google、Microsoft などの大手テック企業が最小限のコストで AB 1043 を満たすケースとは対照的です。プロジェクトの FAQ は法的問題、コンプライアンス状況、および州最高検事への罰金可能性に関する一般的な質問に対応しています。 最後に Ageless Linux は裁判記録を取得するために、Raspberry Pi または USB ドライブを子供へ配布したことによる **$7,500 の罰金** をカリフォルニア州最高検事に請求し、AB 1043 が小規模オープンソースプロジェクトにどのように適用されるかを明確にすることを目的としています。サイトには法的問い合わせや報道関係者向けの連絡先情報(John McCardle、BDFL、FFwF Robotics LLC)が掲載されています。 ---

2026/03/15 6:27

**Show HN:Han – Rustで書かれた韓国語プログラミング言語**

## Japanese Translation: ## 要約 ハンは静的型付けでコンパイルされるプログラミング言語で、キーワードはすべて韓国語で記述されています(例:**함수**、**만약**、**반복**、**변수**)。コンパイラはRustで実装され、LLVM IRを生成し、clangがそれをネイティブバイナリに変換します。ツリー走査型インタープリタ(`hgl interpret`)により、すぐに実行して迅速な試験が可能です。 ハンの型システムは静的で、5つのプリミティブ型を持ちます—정수 (int)、실수 (float)、문자열 (string)、불 (bool)、그리고 없음 (void)。また配列・構造体・クロージャ・パターンマッチング・エラーハンドリング・ファイルI/O・フォーマット文字列・モジュール・ジェネリクス、組み込み数学関数もサポートしています。現在、配列と構造体はインタープリタのみで扱われており、コンパイラの完全なサポートは計画中です。 開発者はハンを REPL(`hgl repl`)、LSP サーバー(`hgl lsp`)によるエディター上のホバー/補完、およびさまざまな CLI コマンド:`interpret`、`build`、`run`、`repl` で操作できます。VS Code 統合は `editors/vscode` ディレクトリにあります。インストールには Rust(≥1.70)と clang が必要で、他の外部コンパイラ依存はありません。 現在の制限としては、タプル・列挙型・非同期/並行処理・ネットワーキング・サブプロセス、および配列/構造体の完全なコンパイルサポートが欠如しています。これらのギャップは今後の開発優先事項を示しています。

2026/03/15 8:10

エアバスは無人戦闘機を二機開発中です。

## Japanese Translation: Airbus は、2029 年までにドイツ空軍へ運用可能な無人協調戦闘機(UCCA)を納入する予定であり、これは Kratos Defense & Security Solutions の Valkyrie プラットフォーム上に構築され、Airbus の Multiplatform Autonomous Reconfigurable and Secure (MARS) ミッションシステムと AI‑有効化された MindShare ソフトウェアを備えています。 MARS システムは、人有人機と無人機の全グループを動的および非動的ミッションで統合して調整することができます。 **主要技術仕様:** - 元の UCCA は長さ 9.1 m、翼幅 8.2 m、航続距離 >5,000 km、MTOW 約 3 t、最大高度 45,000 ft。初飛行は 2019 年に実施されました。 - ドイツ版の初飛行は 2026 年に予定されています。 このパートナーシップには、Airbus と Rafael が Eurofighter コマンド機上で Litening 5 Advanced Targeting Pod をアップグレードし、クロスプラットフォーム接続性と戦闘致死率を向上させる作業も含まれます。 Airbus のエグゼクティブ・マーコ・ガンブラッハトは、「信頼できる主権的な戦闘能力を手頃な価格で提供する」ことの重要性を強調し、Kratos のスティーブ・フェンドリーは「ミッション化された Valkyrie は単独でも、チームとしても、人有人機と無人機の協同作戦においても利用可能である」と述べています。 この取引はドイツにタイムリーかつ大量展開が可能なドローンソリューションを提供し、AI 主導型多プラットフォーム戦闘システムへのより広範な転換を示しています。

**型消去(Type Erasure)の導出** - **目的** - 実行時に型パラメータを除去してジェネリックコードを単純化する。 - ジェネリックとレガシー(非ジェネリック)コードの相互運用性を実現する。 - **仕組み** 1. 各型パラメータをその *上限*(境界)が無ければ `Object` に置き換える。 2. バイトコードからジェネリック署名を消去する。 3. 必要に応じて多相性を保つためブリッジメソッドを生成する。 - **結果** - 実行時にコンパイル時の型安全が失われる。 - 消えた型に依存する操作はキャストが必要になる。 - 不正なキャストが起これば `ClassCastException` が発生し得る。 - **実務上のヒント** - 型消去の影響を抑えるため、可能なら境界付きワイルドカード(`<? extends T>`・`<? super T>`)を使用する。 - ジェネリックロジックは別途ヘルパークラスに分離しておくとよい。 - キャストロジックをカプセル化した型安全ビルダーやファクトリーを利用する。 | そっか~ニュース