ブログ 約5分

C++の最高の部分は、これからやってくる

Share this article
C++の最高の部分は、これからやってくる

2011年以降、多くの新機能がC++標準に追加されました。autoやnullptrなどは今や広く使われていますが、比較的珍しいままのものもあります。しかし、最も重要な変更の一部、つまり言語を次のレベルに引き上げる可能性を持つものは、まだ開発途中です。

モジュール(Modules)

レガシーな  

#include

 メカニズムは今も残っており、多くの欠点があります。この興味深い 文書から、そのいくつかを紹介します。

  • コンパイル時間のスケーラビリティ:ヘッダーがインクルードされるたびに、コンパイラはそのヘッダーとそれが推移的にインクルードするすべてのヘッダーのテキストを前処理および解析しなければなりません。このプロセスはアプリケーションのすべての翻訳単位で繰り返されるため、膨大な量の冗長な作業が発生します。 N個の翻訳単位と、各翻訳単位にインクルードされる M 個のヘッダーがあるプロジェクトでは、ほとんどの M x N の作業を実行することになりますが、 M 個のヘッダーは複数の翻訳単位間で共有されています。テンプレートのコンパイルモデルが膨大な量のコードをヘッダーに押し込むため、C++は特にこの問題が深刻です。
  • 脆弱性から、メタクラスの定義とそれを使用する利点を紹介します。 #include ディレクティブはプリプロセッサによってテキストの挿入として扱われるため、インクルード時にアクティブなマクロ定義の影響を受けます。アクティブなマクロ定義のいずれかがライブラリ内の名前と衝突すると、ライブラリAPIが壊れたり、ライブラリヘッダー自体でコンパイルエラーが発生したりする可能性があります。極端な例として、 #define std "The C++ Standard" としてから標準ライブラリヘッダーをインクルードすると、C++標準ライブラリの実装で恐ろしい連鎖的な失敗が発生します。より微妙な実際の問題は、マクロ衝突のために2つの異なるライブラリのヘッダーが相互作用し、ユーザーが #include ディレクティブの順序を変更したり、 #undef ディレクティブを導入して(意図しない)依存関係を断ち切らなければならない場合に発生します。
  • 慣例的な回避策:Cプログラマーは、Cプリプロセッサモデルの脆弱性を回避するために多くの慣例を採用してきました。例えば、インクルードガードは、複数回のインクルードがコンパイルを壊さないようにするために、ほとんどのヘッダーで必要とされます。マクロ名は衝突を避けるためにLONG_PREFIXED_UPPERCASE_IDENTIFIERS のように書かれ、一部のライブラリ/フレームワーク開発者は、(慣例上)マクロにすべきでない「通常の」名前との衝突を避けるために、ヘッダーで __underscored のような名前さえ使用しています。これらの慣例は、C以外の言語から来た開発者にとって参入障壁となり、経験豊富な開発者にとっては定型文であり、ヘッダーを本来あるべき姿よりはるかに醜くしています。
  • ツールの混乱:Cベースの言語では、ソフトウェアライブラリとうまく連携するツールを構築するのが困難です。ライブラリの境界が明確でないからです。どのヘッダーが特定のライブラリに属しているのか、正しくコンパイルされることを保証するにはどの順序でそれらのヘッダーをインクルードすべきか?ヘッダーはC、C++、Objective-C++、あるいはこれらの言語のバリアントのどれか?それらのヘッダーのどの宣言が実際にAPIの一部となることを意図したもので、どの宣言がヘッダーファイルの一部として書かざるを得なかったために存在しているだけなのか?

モジュールは、より堅牢で効率的なセマンティックモデルにより、ライブラリへのアクセスを改善します。ユーザーの視点からは、

import

 宣言を使用するため、コードの見た目はわずかに異なるだけです。プリプロセッサディレクティブの 

#include

の代わりに:

import std; // Module import directive.
int main() {
    std::cout << “Hello World\n”;
}

多数のSTLヘッダーをインクルードする必要はありません。単一のimportで十分であり、よりクリーンなコードになります。モジュールのimportは、

std 

モジュールのバイナリ表現を読み込み、そのAPIをアプリケーションに直接利用可能にします。import宣言に先行するプリプロセッサ定義は、

std

が提供するAPIに影響を与えません。モジュール自体が独立したモジュールとしてコンパイルされているからです。

メタクラス(MetaClass)

Herb Sutterは長年にわたってC++の改善に貢献してきました。昨年、彼はメタクラス機能を提案しました。彼の 記事から、メタクラスの定義とそれを使用する利点を紹介します。

私は「メタクラス」と仮称される実験的な新しいC++言語機能に取り組んできました。これはC++プログラミングをより強力に、そしてよりシンプルにすることを目的としています。

そして、 提案から、メタクラスの定義とそれを使用する利点を紹介します。

メタクラス(仮称)により、プログラマーは新しい種類の効率的な抽象化を書けるようになります。通常のC++ソースコードから通常のC++クラス定義へのカスタム変換を書くことで、ユーザー定義のルール、デフォルト、生成関数などの共通の特性を共有する、ユーザー定義の名前付きクラスサブセットを定義できます。型システムの分岐はありません。生成されたクラスは通常のクラスです。 主な目標: • 言語に組み込まれた型カテゴリであるclass/struct/union/enumを超えて、C++の抽象化ボキャブラリーを拡張する。 • 長年のベストプラクティスを、英語のガイドや書籍ではなく再利用可能なライブラリとして提供できるようにする。暗記すべきルールのリスト(例:抽象基底クラスや値型を書くためにこのコーディングパターンを覚え、ツールに頼って間違いを見つける)ではなく、簡単に採用できるボキャブラリー(例:interface、value)を実現する。 • あらゆる目的のためのコンパイラ強制パターンを書けるようにする。コーディング標準(例:多くのCore Guidelinesの「enforce」ルール)、API要件(例:ハードウェアインターフェースライブラリ、ブラウザ拡張、コールバックメカニズムと連携するためにクラスが従わなければならないルール)、およびクラスのためのその他のあらゆるパターン。 • 多くの新しい「特殊化された型」機能(例:C++11でenum classを導入したように)を、擬似英語の 標準文書用語ではなく通常のライブラリコードとして書けるようにし、同等の使いやすさと効率性を持たせ、通常のツールを使って単体テストやデバッグができ、新しいコンパイラを更新・出荷せずに開発・配布でき、EWG/CWGでは 標準文書用語としてではなく、LEWG/LWGでコードとして審査できるようにする。その結果、コア言語では狭すぎるために標準化されることのないであろう貴重な拡張(例:interface)を、小さな自己完結型ライブラリとして容易に標準化できるようにする。 • プロパティ、イベントコールバック、同様の抽象化など、システムが必要とするが今日のC++では表現できない情報を表現するために、Qt moc、COM MIDL、C++/CXなどの非C++の「サイド言語」や特別なコンパイラを発明する必要性を排除する。

モジュールとメタクラスにより、C++はより強力で使いやすい言語になる可能性があり、将来さらに多くの機能が追加される可能性があります。言語を改善し続けるすべてのC++貢献者に感謝します。C++よ永遠なれ!:)

Share this article