2013-05-13 25 views
24

さまざまな種類の数値配列を扱ういくつかのメソッドを実装する必要があります。通常、私はその仕事にジェネリックスを使用したいと思いますが、Cはそれらを提供しないので、マクロを使ってエミュレートしようとしています。ここでCの擬似ジェネリック

は私がやろうとしているものの例です:

#ifndef TYPE 
#define TYPE int 
#endif 

TYPE get_minimum_##TYPE (TYPE * nums, int len){ 
    TYPE min = nums[0]; 

    for (int i = 1; i < len; i++) { 
     if (nums[i] < min) { 
      min = nums[i]; 
     } 
    } 

    return min; 
} 

しかし、これはコンパイルされません。 clangのエラーメッセージ:

error: expected ';' after top level declarator

Cでこれを行う方法はありますか?それとも手作業であらゆるタイプのためにこれを実装する必要がありますか?あなたは、ヘッダーファイルでこのような何かを行うことができ

+0

c#とjavaのfyiジェネリックスはランタイム機能です。 –

+0

Cで "templates"/"generics"についてもう少し詳しくお知りになりたい場合は、[この質問を読むことができます](http://stackoverflow.com/questions/10950828/simulation-of-templates-in-c )。いくつかの興味深い答えがあります:) – Jehan

答えて

25

// 
// generic.h 
// 

#define TOKENPASTE(x, y) x ## y 

#define GET_MINIMUM(T) TOKENPASTE(get_minimum_, T) 

TYPE GET_MINIMUM (TYPE) (TYPE * nums, size_t len){ 
    TYPE min = nums[0]; 

    for (size_t i = 1; i < len; i++) { 
     if (nums[i] < min) { 
      min = nums[i]; 
     } 
    } 

    return min; 
} 

、その後#includeをそれが必要な各タイプのソース・ファイルでは、例えば:

// 
// generic.c 
// 

#define TYPE int 
#include "generic.h" 
#undef TYPE 

#define TYPE float 
#include "generic.h" 
#undef TYPE 

あなたが実行することでこれをテストすることができます

$ gcc -E generic.c 

int get_minimum_int (int * nums, size_t len){ 
    int min = nums[0]; 

    for (size_t i = 1; i < len; i++) { 
     if (nums[i] < min) { 
      min = nums[i]; 
     } 
    } 

    return min; 
} 

float get_minimum_float (float * nums, size_t len){ 
    float min = nums[0]; 

    for (size_t i = 1; i < len; i++) { 
     if (nums[i] < min) { 
      min = nums[i]; 
     } 
    } 

    return min; 
} 
23

実際には、amを定義することができますacroは、指定された型の関数を生成します。

#define define_get_minimum(T) \ 
T get_minimum_##T(T* nums, int len){ \ 
    T min = nums[0]; \ 
    for (int i = 1; i < len; i++) { \ 
     if (nums[i] < min) { \ 
      min = nums[i]; \ 
     } \ 
    } \ 
    return min; \ 
} 

その後、あなたは(C++テンプレートを使用して、同様のことは、コンパイラによって自動的に行われます)必要な特殊化を定義するためにそのマクロを呼び出すことができます。

define_get_minimum(int) 
define_get_minimum(double) 
define_get_minimum(float) 

C++コンパイラが自動的に行うもう1つのことは、必要なオーバーロード機能を推測することです。あなたはCでそれを持つことはできませんので、それを専門に使っていると言わなければなりません。

int main() 
{ 
    // Define arr as char* array... 
    // Do stuff... 
    int res = get_minimum(int)(arr, 3); 
} 
:あなたは次のようにそれを呼び出すことができる必要があり、その後

#define get_minimum(T) get_minimum_##T 

:あなたは(C++ <>がちょうど()によって置き換えられている)次のマクロを使用して機能するためのテンプレートのような構文をシミュレートすることができます

私はこのコードをテストしませんでしたが、うまくいくはずです。

+0

+1:私はそれをテストしただけで動作するようです。 –

+0

私は最後の呼び出しのスタイルが気に入っていますが、私は大きなマクロなしでこれをアーカイブしようとしていました。私は@気に入っ何fb55まあ@ – fb55

+0

、汎用的かつ大規模ではないが、Cでその互換性はありません:) – Jehan

0

また、switch文以外の関数ポインタ(関数ポインタの配列)を、使用し、配列のインデックスとして、スイッチの引数を渡すことができます。