25

テンプレート関数を持つfileA.hクラスを宣言するものがあるとします。この関数は、(通常のテンプレート関数と同様に) ヘッダー ファイルに直接実装されます。ここで、(for のような)の特殊な実装を(つまり、ヘッダー ファイルではなく) 追加します。classASomeFunc<T>()SomeFunc()SomeFunc<int>()fileA.C

SomeFunc<int>()他のコードから (おそらく別のライブラリからも) 呼び出す場合、ジェネリック バージョンまたは特殊化を呼び出すでしょうか?

クラスと関数が2つのアプリケーションで使用されるライブラリに存在するという問題が現在発生しています。また、あるアプリケーションは特殊化を正しく使用していますが、別のアプリケーションは一般的な形式を使用しています (後で実行時の問題が発生します)。違いはなぜですか?これはリンカーオプションなどに関連している可能性がありますか? これは Linux で g++ 4.1.2 を使用しています。

4

9 に答える 9

23

呼び出し時に表示されないテンプレートの特殊化があると、エラーになります残念ながら、コンパイラはこのエラーを診断する必要はなく、コードで好きなことを行うことができます (標準では、「形式が正しくなく、診断は必要ありません」)。

技術的には、ヘッダー ファイルで特殊化を定義する必要がありますが、ほぼすべてのコンパイラがこれを期待どおりに処理します。これは、新しい「extern テンプレート」機能を使用して C++11 で修正されています。

extern template<> SomeFunc<int>();

これは、特定の特殊化が別の場所で定義されていることを明示的に宣言します。多くのコンパイラはすでにこれをサポートしており、extern.

于 2008-09-12T16:14:26.313 に答える
9

パラメータ付きのプロトタイプをヘッダー ファイルに追加しましたか?

つまり、fileA.h のどこかにあるということです

template<> SomeFunc<int>();

そうでない場合は、おそらくそれが理由です。

于 2008-09-12T15:44:57.757 に答える
3

私はgcc4で同じ問題を抱えていました.これが私がそれを解決した方法です. 以前のコメントで私が信じさせられたものよりも簡単な解決策でした。以前の投稿のアイデアは正しかったのですが、構文がうまくいきませんでした。


    ----------header-----------------
    template < class A >
    void foobar(A& object)
    {
      std::cout << object;
    }

    template <> 
    void foobar(int);

    ---------source------------------
    #include "header.hpp"

    template <>
    void foobar(int x)
    {
      std::cout << "an int";
    }

于 2009-04-24T18:50:39.470 に答える
2

仕様によると、特殊化された関数テンプレートは、現在サポートされているコンパイラ (Comeau を除く) がない (または近い将来に計画されている) テンプレート定義でfileA.Cない限り、決して外部で呼び出されるべきではありません。export

一方、関数テンプレートがインスタンス化されると、テンプレートではなくなった関数がコンパイラに表示されます。GCC は、異なるコンパイラ ユニット間でこの定義を再利用する可能性があります。標準では、各テンプレートは特定の型引数のセットに対して 1 回だけインスタンス化されると規定されているためです [temp.spec]。それでも、テンプレートはエクスポートされないため、これはコンパイル ユニットに限定する必要があります。

GCC は、インスタンス化されたテンプレートのリストをコンパイル ユニット間で共有する際に、ここでバグを明らかにする可能性があると思います。通常、これは合理的な最適化ですが、正しく行われていないと思われる関数の特殊化を考慮する必要があります。

于 2008-09-12T15:59:00.547 に答える
1

Anthony Williams が言うように、extern template構文はこれを行うための正しい方法ですが、彼のサンプル コードは不完全で複数の構文エラーがあるため、ここに完全な解決策があります。

ファイルA.h:

namespace myNamespace {
  class classA {
    public:
      template <class T> void SomeFunc() { ... }
  };

  // The following line declares the specialization SomeFunc<int>().
  template <> void classA::SomeFunc<int>();

  // The following line externalizes the instantiation of the previously
  // declared specialization SomeFunc<int>(). If the preceding line is omitted,
  // the following line PREVENTS the specialization of SomeFunc<int>();
  // SomeFunc<int>() will not be usable unless it is manually instantiated
  // separately). When the preceding line is included, all the compilers I
  // tested this on, including gcc, behave exactly the same (throwing a link
  // error if the specialization of SomeFunc<int>() is not instantiated
  // separately), regardless of whether or not the following line is included;
  // however, my understanding is that nothing in the standard requires that
  // behavior if the following line is NOT included.
  extern template void classA::SomeFunc<int>();
}

ファイルA.C:

#include "fileA.h"

template <> void myNamespace::classA::SomeFunc<int>() { ... }
于 2013-09-11T13:24:36.677 に答える
1

Microsoft C++ で、インライン関数の実験を行いました。異なるソースで互換性のないバージョンの関数を定義するとどうなるか知りたかったのです。デバッグ ビルドとリリース ビルドのどちらを使用しているかによって、異なる結果が得られました。デバッグでは、コンパイラはインライン化を拒否し、リンカーはソース内のスコープに関係なく同じバージョンの関数をリンクしていました。リリースでは、コンパイラはその時点で定義されていたバージョンをインライン化し、異なるバージョンの関数を取得しました。

どちらの場合も、警告はありませんでした。私はこれを疑ったので、実験を行いました。

テンプレート関数は、他のコンパイラと同じように動作すると思います。

于 2008-09-12T16:10:25.777 に答える
0

@[アンソニー・ウィリアムズ]、

externテンプレート宣言とextern templateインスタンス化を混同していませんか? 私が見たところ、特殊化(暗黙的なインスタンス化を意味する)ではなく、明示的なインスタンス化にのみextern template使用できます。[temp.expl.spec] はキーワードについて言及していません:extern

explicit-specialization :
    template< >宣言

于 2008-09-12T16:35:47.697 に答える
0

特殊化されたテンプレート関数もヘッダー ファイルにリストされていない限り、他のアプリケーションは特殊化されたバージョンを認識しません。SomeFunc<int>()解決策は、ヘッダーへの追加でもあります。

于 2008-09-12T15:43:32.690 に答える
0

Brandon: それは私が思ったことです - 特殊化された関数は決して呼び出されるべきではありません。これは、私が言及した 2 番目のアプリケーションに当てはまります。ただし、最初のアプリは、特殊化がヘッダー ファイルで宣言されていなくても、明らかに特殊化されたフォームを呼び出します。

私は主にここで啓蒙を求めます:-)最初のアプリは単体テストであり、テストではなく実際のアプリでバグが発生するのは残念です...

(PS: この特定のバグは、ヘッダーで特殊化を宣言することで修正しましたが、他にどのような同様のバグがまだ隠されている可能性がありますか?)

于 2008-09-12T15:47:38.327 に答える