简体   繁体   English

C ++类模板专业化

[英]C++ Class Template Specialization

I am new to programming in C++ and I have encountered a problem that I cannot seem to solve when enforcing separate compilation. 我是C ++编程的新手,在执行单独的编译时遇到了似乎无法解决的问题。 I am trying to specialize my class tokenize to add a dtor for a specific type ( istream ). 我正在尝试对我的类tokenize进行专门tokenize ,以为特定类型( istream )添加一个dtor。 I have the following: 我有以下几点:

#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

... and: ...和:

#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>;

... however I get the following error: ...但是我得到以下错误:

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

I am compiling with g++. 我正在使用g ++进行编译。 If someone can kindly point out what I am missing and a possible explanation then that would be fantastic. 如果有人可以指出我所缺少的内容以及可能的解释,那就太好了。 I am confused how templates work with separate compilation (defns/decl separated). 我很困惑模板如何与单独的编译(defns / decl分开)一起工作。

[temp.expl.spec]/5 states: [temp.expl.spec] / 5状态:

Members of an explicitly specialized class template are defined in the same manner as members of normal classes, and not using the template<> syntax. 显式专门化的类模板的成员以与普通类的成员相同的方式定义,而不使用template<>语法。 The same is true when defining a member of an explicitly specialized member class. 当定义显式专门的成员类的成员时,也是如此。 However, template<> is used in defining a member of an explicitly specialized member class template that is specialized as a class template. 但是, template<>用于定义专门化为类模板的显式专门化成员类模板的成员。

It also provides the following example (I'll only quote some excerpts): 它还提供了以下示例(我仅引用一些摘录):

 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() { /∗ ... ∗/ } 

As far as I know, once you've explicit specialized a class template, you've created a "normal class". 据我所知,一旦您明确地专门化了一个类模板,就创建了一个“普通类”。 It's obviously not a template any more (you cannot create classes from the specialization), but a type with some <..> in its name. 显然,它不再是模板(您无法通过专业化创建类),而是名称中带有一些<..>的类型。

In your case, that just means leave out the template<> before 在您的情况下,这仅意味着先忽略template<>

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

With regard to your request on clarification of the combination of separate compilation with templates: 关于澄清单独编译与模板结合的要求:

When you use a class template to create an object (eg std::vector<int> v ) or call a function template (eg std::sort(begin(v), end(v)) ), you're dealing with specializations of the templates. 当您使用类模板创建对象(例如std::vector<int> v )或调用函数模板(例如std::sort(begin(v), end(v)) )时,您正在处理模板的专业化 std::vector<int> is a specialization of the class template std::vector . std::vector<int>是类模板std::vector

When a specialization is required in a TU, it might be necessary to produce it from the class template. 当TU中需要特殊化时,可能有必要从类模板中生成特殊化。 This is called instantiation . 这称为实例化 An explicitly specialized template won't be instantiated implicitly (it already is specialized). 一个显式专门化的模板不会被隐式实例化(它已经专门化的)。 That is, your specialization tokenizer<ifstream> doesn't have to be instantiated in any TU. 也就是说,您的专业化tokenizer<ifstream>不必在任何TU中实例化。

Templates itself don't work with separate compilation for these reasons. 由于这些原因,模板本身不能与单独的编译一起使用。 However, you can use explicit instantiations and explicit specializations to provide the benefits of separate compilation for specializations of templates. 但是,您可以使用显式实例化和专业化明确为模板提供单独编制的好处。 For example: 例如:

[header.hpp] [header.hpp]

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

[impl.cpp] [impl.cpp]

#include "header.hpp"

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

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

[main.cpp] [main.cpp中]

#include "header.hpp"

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

In main.cpp we couldn't instantiate the definition of foo , as the definition is not available. 在main.cpp中,我们无法实例化foo的定义,因为该定义不可用。 We could instantiate the declaration. 我们可以实例化声明。 There's also an explicit instantiation declaration, which prevents any implicit instantiation. 还有一个显式的实例化声明,可以防止任何隐式的实例化。 In another TU (impl.cpp), we did instantiate foo<int> via an explicit instantiation definition . 在另一个TU(impl.cpp)中,我们通过显式实例化定义实例化了foo<int> This requires the definition of f to exist and instantiates the definition. 这要求f的定义存在并实例化该定义。 The rest is similar to normal functions: We have two declarations and one definition. 其余的与普通函数相似:我们有两个声明和一个定义。

Similarly, for class templates: If the definition of a class is required in a TU, we need to either instantiate the template or we need to have an explicit specialization (an explicit instantiation definition is not possible here AFAIK). 类似地,对于类模板:如果TU中需要类的定义,则我们需要实例化模板,或者需要具有显式的特殊化(此处无法使用显式的实例化定义AFAIK)。 This is exactly the OP's example. 这正是OP的示例。

If the definition of the class is not required, we can use something similar to the PIMPL idiom: 如果不需要类的定义,我们可以使用类似于PIMPL方法的东西:

[header.hpp] [header.hpp]

template<class T>
class foobar;

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

[impl.cpp] [impl.cpp]

#include "header.hpp"

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

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

[main.cpp] [main.cpp中]

int main()
{
    s obj;
    obj.f();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM