C ++テンプレートは単なるマクロの一種ですか?


27

このようなC ++テンプレートとC#/ Javaジェネリックのさまざまな比較から、

https://stackoverflow.com/questions/31693/what-are-the-differences-between-generics-in-c-and-java-and-templates-in-c/31929#31929

C ++テンプレートは、コンパイルではなく、何らかの種類の前処理(解析前のプレーンテキスト置換)によって実装されているという認識を得ました。C ++テンプレートの型チェックはCマクロに似ているためです。エラーがある場合、それらはテンプレート自体からではなく、テンプレートコードブロックを処理した後に生成されたコードからのエラーです。言い換えれば、それらはCのマクロの一種の上位バージョンにすぎません。

次に、これをサポートする他のいくつかの事実を見つけました-

  • C ++テンプレートが前処理によって実装される場合、動的リンク(.dllを使用)に問題があると思いました。そして、クイックグーグルがこれをサポートしました。

  • もう1つのポイントは、整数定数を引数としてテンプレートに渡すことができるということです。また、何らかの再帰をサポートします。ただし、この再帰は、コンパイルされたアセンブリ/マシンコードにはありません。再帰的なことは、すべての再帰呼び出しに対して関数を生成することにより、コンパイル時に管理されます。したがって、より大きく、より高速な実行可能バイナリを持ちます。

Cマクロとは異なりますが、いくつかの優れた機能があります。しかし、C ++テンプレートは何らかの前処理で実装されていませんか?これは異なるC ++コンパイラでどのように実装されていますか?


19
いや。C ++テンプレートがコンパイルされます。
エドワードストレンジ

2
「前処理」の定義は何ですか?そして「コンパイル」の?「前処理」の十分に広い定義には、コンパイラが行うすべてが含まれます。結局のところ、コンパイラは実際にソースを実行する前に処理するだけです。
ジェームズマクネリス

@James McNellis IMHO前処理とコンパイルのために行われた他のすべての処理を区別できるのであれば、私の質問を理解するだけで十分です。プリプロセッサを明確にするために-en.wikipedia.org/wiki/Preprocessor#Lexical_preprocessors
グルシャン

6
その形式の前処理を参照している場合、いいえ、C ++テンプレートは、単にある種の美化されたマクロではありません。
ジェームズマクネリス

1
テンプレート言語は実際には完全に調整されているので、拡張されたマクロ以上のものです。
davidk01

回答:


9

C ++テンプレートは、一種の馬鹿げたLisp(またはそれ以上のScheme)マクロです。コンパイル時に評価するチューリング完全言語ですが、その言語から基礎となるC ++環境へのアクセスがないため、厳しく制限されています。そのため、はい、C ++テンプレートは、生成されるコードとの相互作用が非常に限定された、何らかの形式の前処理と見なすことができます。


2
「しかし、その言語から基礎となるC ++環境へのアクセスがないため、厳しく制限されています。」 - どういう意味ですか?このステートメントを解析しようとしましたが、失敗しました。
quant_dev

2
オム、実際... github.com/kmichel/bf0x
アントン

3
@ SK-logic:余談ですが、C ++ 11 C ++です。ただし、同じ言語の異なるバージョンを(言語的に)異なる言語として扱う場合を除きます。
ジョンパーディ

3
@Jon Purdy、C ++ 11は、この回答の時点では(公式には)存在していませんでした。今日では、データ構造の分解、ライブラリ関数の使用など、より複雑な例があります。
SKロジック

1
@ SK-logic:Lispのようなマクロを使用したC ++の実装を知っていますか?テンプレートの制限にうんざりしています。C ++の例- haXeの中に強力なマクロシステムとスタイル構文言語:haxe.org/manual/macros。(私はC ++をその目的に使用しているので、私を助けません-8ビットマイクロコントローラをプログラミングします;他のものにはより良い言語があります)。
pfalcon

41

おそらく最大の違いは、C ++テンプレートがコンパイルの一部である間に、他のコンパイルが実行される前に、Cマクロが前処理段階で展開されることです。これは、C ++テンプレートがタイプ認識とスコープなどを意味し、単純なテキスト置換ではないことを意味します。実際の関数にコンパイルできるため、マクロが抱える問題のほとんどを回避できます。タイプを認識することは、それらが一般的または特殊化できることを意味します。たとえば、swapテンプレート関数を提供するのが簡単で、オブジェクトがヒープメモリを管理する場合でもうまく機能する特殊化を簡単に書くことができます。

したがって、C ++テンプレートは、マクロと同じ意味での前処理ではなく、Cマクロの一種ではありません。また、Cマクロを使用してテンプレートの機能を複製することはできません。

テンプレートは、リンクされたライブラリではなくヘッダーファイルに存在しますが、.dllを提供している場合は、使用するヘッダーファイルも提供していると考えられます。


12
ヘッダーファイルに存在する必要はありません(これは、ヘッダーファイルを使用するための最も単純な手法です)。それらをソースファイルで定義し、ソースファイル(コンパイル単位)でテンプレートのインスタンス化を手動で強制できます。リンクすると、通常どおりインスタンス化が行われます(これは、テンプレートを特定のタイプに制限し、すべての汎用タイプを許可しない手法です)。
マーティンヨーク

@Martin:このテクニックが(サポートされている間)標準によって実際に明示的にサポートされているかどうかはわかりません。そうでなければ、すべてのコンパイラーがexportすでに実装しているでしょう。私はそれが関数でうまくいくことを知っていますが、クラスではうまくいかないと思います:サイズをどのように知っていますか?
マチューM.

@Matthieu M:これはexportキーワードとは関係ありません。「明示的な」テンプレートのインスタンス化を扱い、標​​準で適切に定義されています。
マーティンヨーク

2
@Matthieu M .:コンパイラが関数のシグネチャを知っていて、リンカが実装を見つけることができれば、すべてがクールです。これは、関数がテンプレート関数であるかどうかに関係なく適用されます。実際には、特定のインスタンス化を強制することは通常、それが価値があるよりも多くの作業であるため、それらは通常ヘッダーファイルに存在しますが、Martinは代替に注目することで正しいです。
デビッドソーンリー

確かに、特殊な機能に対して機能することは知っています。しかし、クラスでは機能しないことも確信しています。これが私のポイントでした。特殊なクラスのメソッドでも機能すると思いますが、これが標準かどうかはわかりません。
マチューM.

5

それらの実装方法は重要ですか?初期のC ++コンパイラは、コードをacコンパイラに供給する単なるプリプロセッサでした。C++が単なる美化されたマクロであることを意味するものではありません。

テンプレートは、複数の型のコードを実装するための、より安全で、より効率的で、特化可能な(実際の言葉だとは思わない)方法を提供することにより、マクロの必要性を取り除きます。

cには型コードをテンプレート化するさまざまな方法がありますが、単純な型を超えてしまうと、どれも非常に便利ではありません。


C ++が栄光のマクロであるとは言いませんでした。私はC ++を高く評価しています。好奇心が強いだけです。
グルシャン

2
@Gulshan:いいえ、あなたはそれについて何も言わなかった。それにもかかわらず、それは初期のC ++コンパイラの動作です(CFrontは単なるマクロプリプロセッサではなくコンパイラのようなものである点を除く)。C++テンプレートに関するあなたの声明は、初期のC ++自体にも当てはまります。
デビッドソーンリー

CFront C ++からCにコンパイルされます。プリプロセッサとコンパイラの境界は明確に定義されています。コンパイラは、構文解析、AST構築などにより入力を理解しようとしますが、プリプロセッサはそうではありません。
ジョンパーディ

1
Davidが意味したのは、C ++の基礎となるサブセットがあり、テンプレートがこのサブセットのプログラムを一般化するために使用されるある種のマクロと考えることができ、さらに別のステージとしてコンパイルできることだと思います。
ジョルジオ

5

いくつかの違いがあります。たとえば、テンプレートを使用して、必要なときに関数のオーバーロードをインスタンス化できますが、マクロでは、コンパイラが認識できるようにするために、可能なオーバーロードごとにマクロを1回展開する必要があります。未使用コードの。

別の違いは、テンプレートが名前空間を尊重することです。


2

私見、C ++テンプレート、Cマクロは、2つのまったく異なる問題を解決するためのものでした。元のC ++標準テンプレートライブラリは、コンテナクラス(配列、リンクリストなど)をそれらに一般的に適用される一般的な関数(並べ替えや連結など)から明確に分離するメカニズムでした。効率的なアルゴリズムとデータ構造の抽象表現を使用すると、特定のデータで機能する関数を最適に実装する方法の当て推量が大幅に少なくなるため、コードの表現力が高まります。Cマクロは、インラインコードで言語を「拡張」する手段を提供するという点で、Lispマクロで通常見られるものとはるかに一致していました。クールなことは、C ++標準ライブラリがテンプレートの機能を拡張して、Cで#defineを使用しているものの大部分をカバーすることです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.