2

注:次のコードは不正ですが、準拠するコンパイラはそれを拒否する必要はありません(拒否しないものもあります)。

私が使用しているライブラリには、のテンプレート関数宣言とinFooのテンプレート関数定義があります。Barfoobar.h

template<class C> int Foo();

template<class C> int Bar() {
  return Something(  Foo<C>()  );
}

意図は、他のコードが次のように使用できるようにすることです。

#include "foobar.h"

int main() {
  Bar<MyClass>();
  return 0;
}

// Ideally, the usage (above) and the definition (below)
// would/could be in different translation units. 

template<> int Foo<MyClass>() { return 5; }

質問: この作業を合法的に行う方法はありますか?


問題は (私が物事を正しく理解している場合) コンパイルしても、これは技術的に違法であるということです:明示的な特殊化と の使用の両方が定義としてカウントされるため、 ODRBar<MyClass>に違反します。使用例。

このパターンを使用してパラメーター化する理由Fooは、スタイル ガイドに従う必要があるため、 の定義の前に何かが字句的に含まれていることを確認する唯一の方法は、Barによって含まれていることfoobar.hです。しかし(説明する必要はないと思う理由で)それは初心者です。

4

3 に答える 3

3

これを合法的に機能させる方法はありますか?

はい、使用する前に特殊化を宣言してください。ファイル内の特殊化とメインの順序を入れ替えるだけで、提供した例でこれが行われます。ただし、この例では、他の TU が宣言せずに特殊化を使用していないことを確認する必要があります。

通常、これらの特殊化はヘッダーで宣言する必要があります。

あなたの例の範囲内で(つまり、根本的な変更はありません)、これを機能させる方法は他にありません。

于 2011-05-04T16:46:53.747 に答える
1

これはリンクをコンパイルし、VS2008 と gcc 4.5.2 の両方で実行します。

template<class C> int Foo();

int Something(int i ){ return i; }

template<class C> int Bar() {
    return Something(  Foo<C>()  );
}

class MyClass{};
class FooClass{};

// Update:
// Declaration of a specialisation.
template<> int Foo<MyClass>();

int Zoo(){
    return Something(  Foo<MyClass>()  );
}

#include <iostream>

int main() {
    std::cout << Bar<MyClass>() << std::endl;
    std::cout << Zoo() << std::endl;
    std::cout << Bar<FooClass>() << std::endl;
    return 0;
}

// Definitions of specialisations.
template<> int Foo<MyClass>() { return 5; }
template<> int Foo<FooClass>() { return 6; }

出力は次のとおりです。

5
5
6

これが機能する理由は、宣言されているだけであるにもかかわらず、テンプレート関数Fooにはリンカーで使用できる 2 つの必要な定義があるためです。
コンパイル時に、コンパイラは の定義をmain確認すると、 の特殊化を作成できますがBar、 の特殊化は作成できませんFoo。この場合、 と への関数呼び出しを作成するだけFoo<MyClass>()ですFoo<FooClass>()
後で、コンパイラはFooコンパイル対象の特殊化を見つけ、オブジェクト ファイルに残しますが、その時点では他に何もしません。リンカーが実行されると、必要なものがすべて見つかります。

更新:
なぜこれが違法なのかはわかりませんが、何らかの理由でコンパイルして実行しているようです。

于 2011-05-03T21:06:13.933 に答える
1

テンプレート関数を特殊化することはできないため、これは合法ではありません。

次のようなことができます:

template< typename T >
struct foo
{
  static int doSomething() {return 0;}
};
template< >
struct foo<int>
{
  static int doSomething() {return 5;}
};
于 2011-05-03T20:39:36.720 に答える