27

これは、 「テンプレート内でextern-「C」関数型へのポインターをtypedefすることは可能ですか?」に対する回答のフォローアップ質問です。

g++このコードは、Visual C / C ++、およびComeau C / C ++でコンパイルできず、基本的に同じエラーメッセージが表示されます。

#include <cstdlib>

extern "C" {
    static int do_stuff(int) {
        return 3;
    }

    template <typename return_t_, typename arg1_t_>
    struct test {
        static void foo(return_t_ (*)(arg1_t_)) { }
    };
}

int main()
{
    test<int, int>::foo(&do_stuff);
    return EXIT_SUCCESS;
}

g ++は「エラー:Cリンケージのあるテンプレート」と言い、Visual C / C ++はコンパイラエラーC2894を出し、Comeau C / C ++は「エラー:この宣言には外部の「C」リンケージがない可能性があります」と言います。

事は、すべてが満足しているということです:

#include <cstdlib>

extern "C" {
    static int do_stuff(int) {
        return 3;
    }

    struct test {
        static void foo(int (*)(int)) { }
    };
}

int main()
{
    test::foo(&do_stuff);
    return EXIT_SUCCESS;
}

C ++標準のセクション7.5、リンケージ仕様は次のように述べています。

クラスメンバーの名前およびクラスメンバー関数のメンバー関数タイプについては、AC言語リンケージは無視されます。

そしてそれは例さえ与えます:

extern "C" {
    class X {
        void mf(); // the name of the function mf and the member
                // function's type have C++ language linkage
        void mf2(void(*)()); // the name of the function mf2 has C++ language
                // linkage; the parameter has type pointer to C function
    };
}

テンプレートが外部「C」ブロックで許可されている場合、インスタンス化のメンバー関数はC++リンケージを持ちます。

では、なぜC++98標準状態の第14章テンプレートを実行するのでしょうか。

テンプレート名にはリンケージ(3.5)が含まれる場合があります。テンプレート、テンプレートの明示的な特殊化(14.7.3)、およびクラステンプレートの部分的な特殊化には、Cリンケージがあってはなりません。

テンプレートにリンクがあるとはどういう意味ですか?テンプレートリンケージとは何ですか?

クラスに問題がなく、テンプレートのインスタンス化のすべてのメンバー関数(デフォルトのコンストラクタ、デストラクタ、および代入演算子のオーバーロード)にC ++リンケージがあるのに、Cリンケージを持つテンプレートを使用することが明示的に禁止されているのはなぜですか?

4

5 に答える 5

18

テンプレートは実際のコードではありません。テンプレート パラメーターがわかっている場合にコードを生成する方法について、コンパイラーへのガイドラインにすぎません。そのため、使用しようとするまで実際には存在しません。存在しないものへのリンクを提供することはできません。

于 2011-02-02T17:34:39.023 に答える
12

テンプレートがリンケージを持つ「可能性がある」とはどういう意味ですか? テンプレート連携とは?

すべての名前は、外部リンケージ、内部リンケージを持つか、またはリンケージを持たない (C++03 §3.5p2) のいずれかですが、これは言語リンケージと同じリンケージではありません。(紛らわしいことはわかっています。C++0x では、リンケージによって状況が大きく変わります。) テンプレート引数として使用されるものには、外部リンケージが必要です。

void f() {
  struct S {};
  vector<S> v;  // Not allowed as S has internal linkage.
}

C++98 には §14p4 の引用部分に「may」が含まれていますが、C++03 では「may」が削除されていることに注意してください。これは、テンプレートに内部リンケージを与えるコンテキストでテンプレートを宣言できないためです。

void f() {
  // Not allowed:
  template<class T>
  struct S {};
}
于 2011-02-02T18:49:31.950 に答える
6

extern Cテンプレートが使用する名前マングリングを無効にするため

テンプレートが名前マングリングで実装されていることを確認するには、コンパイルおよび逆コンパイルします。

#include <cassert>

template <class C>
C f(C i) { return i; }

int main() {
    f<int>(1);
    f<double>(1.5);
}

と:

g++ -c -g -std=c++98 main.cpp
objdump -Sr main.o

出力には次が含まれます。

int main() {
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   48 83 ec 10             sub    $0x10,%rsp
    f<int>(1);
   8:   bf 01 00 00 00          mov    $0x1,%edi
   d:   e8 00 00 00 00          callq  12 <main+0x12>
            e: R_X86_64_PC32    _Z1fIiET_S0_-0x4
    f<double>(1.5);
  12:   48 b8 00 00 00 00 00    movabs $0x3ff8000000000000,%rax
  19:   00 f8 3f 
  1c:   48 89 45 f8             mov    %rax,-0x8(%rbp)
  20:   f2 0f 10 45 f8          movsd  -0x8(%rbp),%xmm0
  25:   e8 00 00 00 00          callq  2a <main+0x2a>
            26: R_X86_64_PC32   _Z1fIdET_S0_-0x4
}
  2a:   b8 00 00 00 00          mov    $0x0,%eax
  2f:   c9                      leaveq 
  30:   c3                      retq

callqすべてが のような変な名前を呼ぶように作られていることに注意してください_Z1fIiET_S0_

同じことが、関数のオーバーロードなど、名前マングリングに依存する他の機能にも当てはまります。

より詳細な回答を次の場所に書きました: What is the effect of extern "C" in C++?

于 2015-07-01T12:46:22.873 に答える
3

テンプレート関数名は追加情報で装飾する必要があり、extern "C"装飾をオフにするためです。の目的はextern "C"、C リンケージで呼び出すことができる関数を宣言できるようにすることです。これは、明らかにテンプレート関数では機能しません。

于 2011-02-02T17:34:34.700 に答える
-4

Cにはテンプレートがないからです。

于 2011-02-02T17:33:49.763 に答える