0

私は C++ でプログラミングするのが初めてで、別のコンパイルを強制するときに解決できないように見える問題に遭遇しました。クラスを特殊tokenize化して、特定の型 ( ) の dtor を追加しようとしていistreamます。私は次のものを持っています:

#ifndef __TOKENIZER_H__
#define __TOKENIZER_H__

#include <fstream>
#include <string>

template <class T>
class base {
  // ... some methods/member variables.
};

template <class T>
class tokenizer : public base<T> {
  public:
    tokenizer(T &in);
};

template <>
class tokenizer<std::ifstream> : public base<std::ifstream> {
  public:
    tokenizer(std::ifstream &in);
    ~tokenizer();
};

#endif

... と:

#include "tokenizer.h"

#include <fstream>
#include <iostream>
#include <locale>

using std::ifstream;
using std::istream;
using std::string;

// [BASE]

// ... code for those functions.

// [TOKENIZER]

// See header file.
template <class T>
tokenizer<T>::tokenizer(T &in) : base<T>(in) { }

// See header file.
template <>
tokenizer<ifstream>::tokenizer(ifstream &in) : base<ifstream>(in) { }

// See header file.
template <>
tokenizer<ifstream>::~tokenizer() {
  delete &(base<ifstream>::in);
}

// Intantiating template classes (separate compilation).
template class base<std::ifstream>;
template class base<std::istream>;
template class tokenizer<std::ifstream>;
template class tokenizer<std::istream>;

...しかし、次のエラーが発生します。

tokenizer.cc:62: error: template-id ‘tokenizer<>’ for ‘tokenizer<std::basic_ifstream<char, std::char_traits<char> > >::tokenizer(std::ifstream&)’ does not match any template declaration
tokenizer.cc:66: error: template-id ‘tokenizer<>’ for ‘tokenizer<std::basic_ifstream<char, std::char_traits<char> > >::~tokenizer()’ does not match any template declaration

g++でコンパイルしています。誰かが私が欠けているものと可能な説明を親切に指摘できれば、それは素晴らしいことです. テンプレートが個別のコンパイル (defns/decl の分離) でどのように機能するか混乱しています。

4

1 に答える 1

4

[temp.expl.spec]/5 状態:

template<>明示的に特殊化されたクラス テンプレートのメンバーは、構文を使用せずに、通常のクラスのメンバーと同じ方法で定義されます。明示的に特殊化されたメンバー クラスのメンバーを定義する場合も同様です。ただし、template<>クラス テンプレートとして特殊化された、明示的に特殊化されたメンバー クラス テンプレートのメンバーを定義する際に使用されます。

また、次の例も提供します (一部の抜粋のみを引用します)。

template<class T> struct A {
    template<class U> struct C { };
};

template<> struct A<int> {
    void f(int);
};

// template<> not used for a member of an
// explicitly specialized class template
void A<int>::f(int) { /∗ ... ∗/ }

template<> template<class U> struct A<char>::C {
    void f();
};
// template<> is used when defining a member of an explicitly
// specialized member class template specialized as a class template
template<>
template<class U> void A<char>::C<U>::f() { /∗ ... ∗/ }

私の知る限り、クラス テンプレートを明示的に特殊化すると、「通常のクラス」が作成されます。これはもはやテンプレートではなく (特殊化からクラスを作成することはできません)、<..>名前に some を含む型です。

あなたの場合、それは単にtemplate<>beforeを除外することを意味します

// See header file.
//template <>
tokenizer<ifstream>::tokenizer(ifstream &in) : base<ifstream>(in) { }

// See header file.
//template <>
tokenizer<ifstream>::~tokenizer() {
  delete &(base<ifstream>::in);
}

分割編集とテンプレートの組み合わせの明確化に関するご要望について:

クラス テンプレートを使用してオブジェクトを作成したり (例: std::vector<int> v)、関数テンプレートを呼び出したりする場合 (例: )、テンプレートの特殊std::sort(begin(v), end(v))化を扱っています。クラステンプレートの特殊化です。std::vector<int>std::vector

TU で特殊化が必要な場合、クラス テンプレートから生成する必要がある場合があります。これはインスタンス化と呼ばれます。明示的に特殊化されたテンプレートは暗黙的にインスタンス化されません (既に特殊化されています)。つまり、tokenizer<ifstream>スペシャライゼーションを TU でインスタンス化する必要はありません。

これらの理由により、テンプレート自体は個別のコンパイルでは機能しません。ただし、明示的なインスタンス化と明示的な特殊化を使用して、テンプレートの特殊化を個別にコンパイルする利点を提供できます。例えば:

[ヘッダー.hpp]

template<class T> void foo(T);
extern template void foo<int>(int);

[impl.cpp]

#include "header.hpp"

template<class T> void foo(T) { return T{} };

template void foo<int>(int); // force instantiation

[main.cpp]

#include "header.hpp"

int main()
{
    foo<int>(42); // no instantiation will occur
}

main.cpp では、定義が利用できないため、 の定義をインスタンス化できませfooんでした。宣言をインスタンス化できます。暗黙的なインスタンス化を防ぐ明示的なインスタンス化宣言もあります。別の TU (impl.cpp) ではfoo<int>、明示的なインスタンス化定義を使用してインスタンス化しました。これには の定義がf存在する必要があり、定義をインスタンス化します。残りは通常の関数と同様です。2 つの宣言と 1 つの定義があります。

同様に、クラス テンプレートの場合: TU でクラスの定義が必要な場合は、テンプレートをインスタンス化するか、明示的な特殊化を行う必要があります (明示的なインスタンス化の定義は、ここではできません)。これはまさにOPの例です。

クラスの定義が不要な場合は、PIMPL イディオムに似たものを使用できます。

[ヘッダー.hpp]

template<class T>
class foobar;

struct s
{
    foobar<int>* p;
    void f();
}

[impl.cpp]

#include "header.hpp"

template<class T> class foobar { int i; }

void s::f() { p = new foobar{42}; }

[main.cpp]

int main()
{
    s obj;
    obj.f();
}
于 2013-10-26T20:53:25.370 に答える