2011-02-01 19 views
8

「C」言語リンケージを使用する関数を取る1つの引数へのポインタのテンプレートに、公開typedefを追加します。テンプレート内にextern- "C" -function型をtypedefすることは可能ですか?

私が試した:

extern "C" { 
    template <typename return_t_, typename arg1_t_> 
    struct test 
    { 
     typedef return_t_ (*C_fun1_t)(arg1_t_); 
    }; 
} 

そして:

template <typename return_t_, typename arg1_t_> 
struct test 
{ 
    extern "C" { 
     typedef return_t_ (*C_fun1_t)(arg1_t_); 
    } 
}; 

そして:

template <typename return_t_, typename arg1_t_> 
struct test 
{ 
    extern "C" typedef return_t_ (*C_fun1_t)(arg1_t_); 
}; 

を成功せず。

私は可能なことを達成しようとしていますか?

+1

これは、extern "C"が別の呼び出し規約を使用するかもしれないものではありません。あなたが考慮しなければならない厄介なことの1つですが、ほとんど起こりません。 'extern" C "'は型システムの一部ではないので、関数ポインタ型は2つを区別しません。これはリンケージ指定子です。つまり、C++ *から作られたポインタを通る呼び出しは、ポインタの参照が 'extern" C "'であるかどうかにかかわらず動作します。これは失敗した可能性のあるCからの呼び出しですが、型システムはこれをチェックしません。 –

+3

@ Steve:それは型システムの一部です。 C++ 03§7.5p1: "異なる言語リンケージを持つ2つの関数型は、それ以外の点で同じであっても、異なる型です。" §5.2.2p1: "関数型が呼び出された関数の定義の関数型の言語リンケージとは異なる言語リンケージを持つ式を介して関数を呼び出すことは定義されていません。" –

+0

@Fred:ああ、OK。申し訳ありませんが、間違った情報をどこから選んだのか分かりません。また、関数ポインタをパラメータとしてとるextern "C"関数を宣言すると、 "C"関数または "C++"関数が使用されますか? g ++はうれしく '-pedantic'のどちらかを使うことができます。 –

答えて

9

C++ 03、§7.5p4:残念ながら

A linkage-specification shall occur only in namespace scope. … A C language linkage is ignored for the names of class members and the member function type of class member functions.

、あなたは、単に現在のC++でこれを行うことはできません。このテキストは最新のC++ 0xドラフトでは変更されていませんが、「テンプレートのtypedef」がそれを達成できるかもしれません。

+0

「テンプレートのtypedef」についてはどこで読むことができますか? –

+0

@DanielTrebbien:「テンプレートエイリアス」は新しい名前のようです。 N3225の§14.5.7と様々な論文。 –

+0

そして、テンプレートエイリアスはこの問題を解決しません。 Cリンケージはテンプレートには適用できません(テンプレートタイプのエイリアスを含む)。 – bames53

1

boost::functiontypedefまたはSTL関数オブジェクトを考えてみてください。あなたはそれを考えるとかなり明白な理由からextern "C"ブロック内にテンプレートを定義することもできません。

+0

@Fred:テンプレート定義をextern "C"ブロック内に置くと、g ++ 4.5.0は "template with C linkage"というエラーを出します。 –

+0

これはコンパイラに固有のものかもしれません...私のソースはこちらhttp://msdn.microsoft.com/en-us/library/95bhc9c2.aspx – AJG85

+0

@DanielTrebbien:標準では何も見えませんが、特にそれらを除外しますが、すべてのコンパイラがそれらを拒否するように見えます)。 (これは私の答えで引用したものを考えれば効果がないので意味がありますが、それは厳しく禁じられているのと同じことです) –

0

typedefからextern "C"を省略すると、すべてうまくいくようです。それは、以下のコンパイル、リンクされ、警告、エラー、または問題なく動作します:

のfoo.c:

#include <stdio.h> 
int foo(int x) { 
    return printf("%x\n", x); 
} 

ます。test.cpp:

extern "C" int foo(int); 

template <typename return_t_, typename arg1_t_> 
struct test 
{ 
    typedef return_t_ (*C_fun1_t)(arg1_t_); 
    C_fun1_t myFn; 
}; 

int main() { 
    test<int, int> t; 
    t.myFn = foo; 
    return t.myFn(5); 
} 

C++の達人のために:私は、CリンケージとC++を区別する細かい点を知らない。このような簡単な例の中に現れない隠された問題はありますか?

+1

これは、g ++では既知の(例えば、http://gcc.gnu.org/bugzilla/show_bug.cgi?id=29038を参照してください)、Comeau C/C++ 4.3.10.1では、エラー "error: *)(int) 'int(\ *)(int)'型のエンティティにC 'を代入することはできません " –

+0

実際にg ++ 4.4.3を使用しています。 – Karmastan

関連する問題