組み込みプロジェクトに取り組んでいて、一度すべてのCで作業してみましたが、我慢できませんでした。非常に冗長だったため、何も読みにくくなりました。また、私が作成した組み込み用に最適化されたコンテナーが気に入りました。これは、安全性が大幅に低下し、#define
ブロックを修正するのが難しくなりました。
C ++では次のようなコードです。
if(uart[0]->Send(pktQueue.Top(), sizeof(Packet)))
pktQueue.Dequeue(1);
になる:
if(UART_uchar_SendBlock(uart[0], Queue_Packet_Top(pktQueue), sizeof(Packet)))
Queue_Packet_Dequeue(pktQueue, 1)
多くの人がおそらくそれでいいと言うでしょうが、1行に2つ以上の「メソッド」呼び出しをしなければならない場合はばかげています。2行のC ++は5行のCになります(80文字の行の長さの制限のため)。どちらも同じコードを生成するため、ターゲットプロセッサが気にするようなものではありません。
ある時(1995年にさかのぼります)、私はマルチプロセッサデータ処理プログラムのためにたくさんのCを書いてみました。各プロセッサが独自のメモリとプログラムを持っている種類。ベンダー提供のコンパイラーはCコンパイラー(ある種のHighC派生物)であり、ライブラリーはクローズドソースであるため、GCCを使用してビルドすることはできませんでした。また、APIは、プログラムが主に初期化/プロセスになるという考え方で設計されました。 /種類を終了するので、プロセッサ間通信はせいぜい初歩的なものでした。
私はあきらめる前に約1か月かかり、cfrontのコピーを見つけ、それをmakefileにハッキングして、C ++を使用できるようにしました。Cfrontはテンプレートさえサポートしていませんでしたが、C ++コードははるかに明確でした。
一般的なタイプセーフなデータ構造(テンプレートを使用)。
Cがテンプレートに最も近いのは、次のような多くのコードを含むヘッダーファイルを宣言することです。
TYPE * Queue_##TYPE##_Top(Queue_##TYPE##* const this)
{ }
次に、次のようなものでそれを引き込みます。
#define TYPE Packet
#include "Queue.h"
#undef TYPE
最初にunsigned char
作成しない限り、これは複合タイプ(たとえば、のキューがない)では機能しないことに注意してくださいtypedef
。
ああ、覚えておいてください。このコードが実際にどこでも使用されていない場合は、構文的に正しいかどうかさえわかりません。
編集:もう1つ、コードのインスタンス化を手動で管理する必要があります。「テンプレート」コードがすべてインライン関数ではない場合は、リンカーが「Fooの複数のインスタンス」エラーの山を吐き出さないように、物事が1回だけインスタンス化されるように制御する必要があります。 。
これを行うには、インライン化されていないものをヘッダーファイルの「実装」セクションに配置する必要があります。
#ifdef implementation_##TYPE
#endif
そして、テンプレートバリアントごとのすべてのコードの1つの場所で、次のことを行う必要があります。
#define TYPE Packet
#define implementation_Packet
#include "Queue.h"
#undef TYPE
また、この実装セクションのニーズがあることを外に標準#ifndef
/ #define
/#endif
あなたは別のヘッダファイル内のテンプレートのヘッダファイルを含むこともできるので、嫌になるほど、しかし、でその後インスタンス化する必要があります.c
ファイル。
うん、それは醜い速くなります。そのため、ほとんどのCプログラマーは試していないのです。
RAII。
特に、複数のリターンポイントを持つ関数では、たとえば、各リターンポイントでミューテックスを解放することを覚えておく必要はありません。
さて、あなたのきれいなコードを忘れて、すべてのリターンポイント(関数の終わりを除く)がsであることに慣れてください:goto
TYPE * Queue_##TYPE##_Top(Queue_##TYPE##* const this)
{
TYPE * result;
Mutex_Lock(this->lock);
if(this->head == this->tail)
{
result = 0;
goto Queue_##TYPE##_Top_exit:;
}
Queue_##TYPE##_Top_exit:
Mutex_Lock(this->lock);
return result;
}
一般的なデストラクタ。
つまり、MyClassに対してd'torを1回作成すると、MyClassインスタンスがMyOtherClassのメンバーである場合、MyOtherClassはMyClassインスタンスを明示的に非初期化する必要はありません。そのd'torは自動的に呼び出されます。
オブジェクトの構築は、同じ方法で明示的に処理する必要があります。
名前空間。
これは実際には簡単に修正できます。すべてのシンボルにプレフィックスを付けるだけです。これは、前に説明したソースの肥大化の主な原因です(クラスは暗黙の名前空間であるため)。Cの人々はこれを永遠に生きてきており、おそらく大したことは何なのかわからないでしょう。
YMMV