2013-07-01 6 views
10

私は、どのプロトタイプをC++に含めるべきかを指定するインラインの方法を望んでいます。たとえば:cとC++のプロトタイプを混在させるためのインラインな方法はありますか?

 
     void ArrayList_insert(ArrayList *arrlst, void *data, int i); 
IS_CPP void ArrayList_insert(ArrayList *arrlst, char *data, int i); 
IS_CPP void ArrayList_insert(ArrayList *arrlst, Buffer *data, int i); 

は、現在、私がやっている:

 
#ifdef __cplusplus 
extern "C" { 
#endif 

....C HEADERS.. 

#ifdef __cplusplus 
} 

....C++ HEADERS... 

#endif 

が、その非常に不便を同じ関数のオーバーロードは、異なる場所にあるため。私はちょうど2つの異なるヘッダーファイルを持つことができますが、それはあまりにも痛みです。したがって、私は上記のようなインラインソリューションを探しています。誰かがそれを行う方法を知っていますか?あなたがC++としてヘッダをコンパイルする場合さて、あなたはすべての3つを取得します

#ifdef __cplusplus 
#define IS_CPP(x) x 
#else 
#define IS_CPP(x) 
#endif 

     void ArrayList_insert(ArrayList *arrlst, void *data, int i); 
IS_CPP(void ArrayList_insert(ArrayList *arrlst, char *data, int i)); 
IS_CPP(void ArrayList_insert(ArrayList *arrlst, Buffer *data, int i)); 

、しかし、あなたはのようにコンパイルした場合:

答えて

14

あなたの考えるよりも簡単です。ヘッダこのタイプの

#ifdef __cplusplus 
#define IS_C(x) extern "C" x ; 
#define IS_CPP(x) x ; 
#else 
#define IS_C(x) x ; 
#define IS_CPP(x) 
#endif 

IS_C (void ArrayList_insert(ArrayList *arrlst, void *data, int i)) 
IS_CPP (void ArrayList_insert(ArrayList *arrlst, char *data, int i)) 
IS_CPP (void ArrayList_insert(ArrayList *arrlst, Buffer *data, int i)) 
+0

これは、関数のオーバーロードをサポートしていないため、コンパイル時にエラーが発生します。 – chacham15

+0

チャチャム15 - あなたは正しいです。私は質問を間違って読んだので、答えを修正しました。 –

+0

これは@ Carl Norumの答えと同じです。 – chacham15

11

確かに、あなたは、関数のようなマクロを使用することにより、ほぼあなたの例のようにそれを行うことができますC、あなたはそれを手に入れるだけです。これらの間で単一のライブラリを共有したい場合は、C++用にコンパイルするときに、C関数にextern "C"修飾子を追加する必要があります。 @ MarkLakataの答えは一つの可能​​な方法を示しています。

+0

+1しかし、末尾に近い括弧を使用せずに行う方法はありますか? (私はちょっと偏心して、泣いています) – chacham15

+0

そうは思いません。 –

+0

-1、これには必要な言語のリンクがありません。 – Potatoswatter

1

あなたは明らかにあなたが求めているものを一緒にハックするプリプロセッサを乱用が、なぜそれを行うことができますか?私がC++を使用していた場合、個人的にはArrayList_insert(mylst, foop, 1);の代わりにmylst.insert(foop, 1);と入力します。言い換えれば、オーバーロードされた関数を呼び出すためにCスタイルを使用することにはほとんどメリットがありませんが、コード作成者が作成した関数呼び出しのスタイルを混在させることは、どちらかというときわめてきれいではありません。

私は、C構造体と同じメンバを持つArrayListクラスを作成し、クラスをC関数とインターフェイスする必要があるときは、可能であれば浅いコピーを作成し、それをC関数に渡してからその構造の情報をクラスにコピーして戻します。

代わりに、C++クラスで構造体をラップし、それをCインタフェース関数に使用することもできます。

構造体のタグの名前がArrayListではなく、構造体のtypedefがC++インタフェースから見えないと仮定して、クラスをC構造体を継承させようとするかもしれません。次に、実際のC構造体のように、このポインタをメンバー関数内から直接渡すことができます。私はこの方法がすべての場合に移植可能であるかどうかは分からないので、データを前後にコピーする必要があっても、可能であれば前者の考え方を実装します。

すべてのアイデアはコードの重複を避け、C++インターフェイスはC関数とC++関数のオーバーロードの混在ではなく、C++コードのように見えます。さらに、インターフェースはいくらか分離されている。追加のヘッダファイルは必要ありませんいずれかのC関数は、いつものようにextern「C」ブロックでラップすることができますよう:

#ifdef __cplusplus 
extern "C" { 
#endif 

struct array_list_tag { 
    ... 
}; 

/* C functions here */ 

#ifdef __cplusplus 
} /* extern "C" */ 

class ArrayList ... 
#else /* !__cplusplus */ 
typedef struct array_list_tag ArrayList; 
#endif 
+0

「すべてのアイデアはコードの重複を避ける」正確に。使用例の例は、Cと重なっているライブラリをC++で作成する場合です。オーバーロードされた関数を呼び出すのが好きですが、統合しているCが必要なものを呼び出す方法が必要です同様に機能する。構造体をクラスにラップするか、その逆にコードの重複量を増やし、プラットフォーム全体のコーディングスタイルに矛盾を追加します。 – chacham15

+0

したがって、Cはすべてのオーバーロードされた関数を呼び出すことができるはずですか?次に、要求されたOPとしてのみCのArrayList_insertの代わりに、ArrayList_insertBuffer、ArrayList_insertString、ArrayList_insertRawDataなどになりましたか? C++インターフェイスは少なくとも一致します...クラスの構造体をラップする場合は、おそらく正しいでしょう。 C++標準には、C++クラスのデータにアクセスできるようにCリンケージの機能が必要なものがあると確信しています。継承、仮想関数、その他のクラスと混合クラスに付随するすべての警告がない限り、 C. –

3

通常のアプローチは、単に最も明白な方法でそれを書くことである:

void ArrayList_insert(ArrayList *arrlst, void *data, int i); 
#ifdef __cplusplus 
void ArrayList_insert(ArrayList *arrlst, char *data, int i); 
void ArrayList_insert(ArrayList *arrlst, Buffer *data, int i); 
#endif /* __cplusplus */ 
@ chacham15として

が指摘し、あなたも

#ifdef __cplusplus 
#define EXTERN_C extern "C" 
#endif /* __cplusplus */ 

、プロジェクト全体ヘッダーで、必要とあなたはEXTERN_CとC-呼び出し可能な機能を飾るする必要があります。

+0

それほど単純ではなく、IMOが本当にクルージングに見せるc関数の '#ifdef __cplusplus extern" c "#endif'宣言が欠落しています。 – chacham15

+0

@ Chacham15:あなたが他のところでコメントしているように、 '#ifdef __cplusplus #define IS_C extern" C "#else #define IS_C#endif'またはそれに類するもの(" EXTERN_C "のような名前を示唆します)は、非常にクリーンな...マクロ内のすべての行をラップするよりもはるかに良い、 '))'、マクロ内でセミコロンを持つか、視覚的に各行から欠落しています。 –

1

実際に定型句を取り除きたい場合、プリプロセッサを使用してそれを行う場合は、パターンを書き留めてください。あなたが持っている一般的なパターンは、通常の関数の宣言は、括弧で囲まれていないカンマを含めることはできませんので、これは動作します

#ifdef __cplusplus 
# define C_PORTABLE_FUNCTION_SET(C_DECLS, CXX_DECLS) \ 
     extern "C" { C_DECLS } \ 
     CXX_DECLS 
#else 
# define C_PORTABLE_FUNCTION_SET(C_DECLS, CXX_DECLS) \ 
     C_DECLS 
#endif 

、だからマクロを作ることができる

extern "C" { 
    void C_accessible_declaration(); // this is all C sees 
} 

void Cxx_accessible_declaration_1(int); 
void Cxx_accessible_declaration_1(long); 

のように見えます。テンプレート(カンマで区切られたテンプレートパラメータを使用)で作業する場合は、C99、C++ 11、およびこれらの標準に先行するさまざまなコンパイラでサポートされている可変長マクロを拡張子として使用できます。

#ifdef __cplusplus 
# define C_PORTABLE_FUNCTION_SET(C_DECLS, ...) \ 
     extern "C" { C_DECLS } \ 
     __VA_ARGS__ 
#else 
# define C_PORTABLE_FUNCTION_SET(C_DECLS, ...) \ 
     C_DECLS 
#endif 

は今、これはCの宣言を使用すると、1つの宣言で複数のオブジェクトを宣言するべきではありません意味裸のカンマを含まない限り動作します。私はそれをC_PORTABLE_FUNCTION_SETと呼んでいますが、それは主に関数宣言での使用には安全ですが、Cのアクセス可能なオブジェクトをextern C内に宣言する必要があることに注意してください。共有されたstructの定義はまったく保護されるべきではありません。 C++ PODの概念によって保護されており、言語リンケージは行われません。

使用法:

#ifdef __cplusplus 
template< typename T, typename U > 
class Buffer { // still use #ifdef for the general case 
    ... 
}; 
#endif 

C_PORTABLE_FUNCTION_SET (
     void ArrayList_insert(ArrayList *arrlst, void *data, int i); 
, /* C++ */ 
     void ArrayList_insert(ArrayList *arrlst, char *data, int i); 

     template< typename T, typename U > 
     void ArrayList_insert(ArrayList *arrlst, Buffer< T, U > &data, int i); 
) 

私はこれを自分でやるだろうとは思わないが、それは慣用的になるために十分に安全と思われます。

関連する問題