4

まず、クラスのヘッダー ファイル、定義のない特殊化宣言 (インターネットからのコード サンプル) を取得しました。

$ 猫 foo.h

template<typename T>
class foo{
public:
  static void init(){
      return;
  }

};

template<>  void foo<int>::init();

次に、テンプレートの特殊化のための 2 つの実装ファイルがあります

$ cat foo_int.cpp 
#include "foo.h"
#include<stdio.h>
template<>
void foo<int>::init(){
    printf("init int foo\n");
}

$ cat foo_float.cpp 
#include "foo.h"
#include<stdio.h>
template<>
void foo<float>::init(){
    printf("init float foo\n");
}

最後に、メインファイルを取得しました

$ cat main.cpp
#include "foo.h"

int main(){
  foo<int>::init();
  foo<float>::init();
}

最適化せずにコンパイルして実行すると、次のようになります。

g++ foo_int.cpp foo_float.cpp main.cpp && a.out
init int foo
init float foo

最適化を追加すると、結果は異なります。

$ g++ foo_int.cpp foo_float.cpp main.cpp -O2 && a.out
init int foo

結果は異なります。インターネットからの説明によると、これはgcc実装の「弱いシンボル」の内部メカニズムによるものですが、私の質問:

  1. 「弱いシンボル」/「強いシンボル」は gcc/g++ の概念ですか、それとも c/c++ 言語仕様の一部です。

  2. デバッグとリリースの結果が異なる場合、これは「弱いシンボル」メカニズムに関する gcc/g++ のバグ/問題であると言えますか? 開発者として、私のデバッグ バージョンがリリース バージョンと異なる動作をするとは思いません。

残念ながら同じエラーが発生しました。これは、C/C++ のデバッグ/リリースの動作が「そうであるべき」「受け入れられる」ケースですか?

4

2 に答える 2

6

言語定義では、使用する前に明示的な特殊化を宣言する必要があります。

テンプレート、メンバー テンプレート、またはクラス テンプレートのメンバーが明示的に特殊化されている場合、その特殊化は、暗黙的なインスタンス化を発生させる特殊化の最初の使用の前に、そのような使用が発生するすべての翻訳単位で宣言する必要があります。 ; 診断は必要ありません。[temp.expl.spec]/6.

foo<float>::init()から呼び出される時点での明示的な特殊化の宣言はありませんが、 では明示的な特殊化mainがあるfoo_float.cppため、プログラムの動作は未定義です。

于 2016-10-11T11:46:17.557 に答える
4

あなたは1 つの定義規則に違反しています — あなたのプログラムにはの 2 つの定義が含まれていますfoo<float>::init

一方の定義はコンパイル単位foo_float.cppで発生し、もう一方の定義はコンパイル単位で発生しmain.cppます。

1 つの定義ルールに違反すると、未定義の動作が発生します。この場合、次のようなことが起こる可能性があります。

  • 最適化をオフにすると、プログラムは実際の関数呼び出しを生成し、リンカーはたまたまfoo_float.cpp実行可能ファイルに関数のバージョンを配置しました。
  • 最適化をオンにすると、コンパイラをコンパイルすると関数がインライン化されます — 当然、関数のバージョンmain.cppがインライン化されます。main.cpp
于 2016-10-11T11:37:17.627 に答える