简体   繁体   English

具有STL容器成员的模板类

[英]template class with STL container member

I'm writing a template class that uses a std::multimap as a member, and getting compile errors. 我正在编写一个使用std :: multimap作为成员的模板类,并得到编译错误。

LocTree.h: LocTree.h:

#pragma once
#include <map>

template <class Loc, class T>
class LocTree
{
public :
         typedef std::multimap<typename Loc, typename T> TreeType;

        LocTree( void );
        ~LocTree( void ) { };
private :
        TreeType db;
};

LocTree.cpp: LocTree.cpp:

#include "StdAfx.h"
#include "LocTree.h"

LocTree< class Loc, class T>::LocTree()
{
}

The compile error (from VC2005) : 编译错误(来自VC2005):

Error     1     error C2079: 'std::pair<_Ty1,_Ty2>::first' uses undefined class 'Loc'     c:\program files (x86)\microsoft visual studio 8\vc\include\utility     53
Error     2     error C2079: 'std::pair<_Ty1,_Ty2>::second' uses undefined class 'T'     c:\program files (x86)\microsoft visual studio 8\vc\include\utility     54

I know I could put the function definitions in the .h but I'm hoping to keep them separate, if it's legal to do so. 我知道我可以将函数定义放在.h中,但我希望将它们分开,如果这样做是合法的。 How do I fix this (probably newbie) problem? 如何解决这个(可能是新手)问题?

Your constructor definition should be: 您的构造函数定义应为:

template<class Loc, class T>
LocTree<Loc,T>::LocTree()
{
}

Also, hoping to keep them separate... - don't - you're wasting your time. 另外,希望将它们分开...-不要-您正在浪费时间。 The only way to keep them separate is to have a definition in a different header which you also include. 使它们分开的唯一方法是在您还包括的不同标头中有一个定义。 So, technically, they are separate, but the implementation is still visible. 因此,从技术上讲,它们是分开的,但是实现仍然可见。

Two points. 两点。 The first is: what is: 首先是:什么是:

typedef std::multimap<typename Loc, typename T> TreeType;

supposed to mean? 应该是什么意思? I don't see what the typename are doing in there; 我看不出有什么typename在那里做; I think you just want: 我想您只想要:

typedef std::multimap<Loc, T> TreeType;

Second, when defining a member function of a class template outside of the class, the syntax is: 其次,在类之外定义类模板的成员函数时,语法为:

template <typename Loc, typename T>
LocTree<Loc, T>::LocTree()
{
}

In other words, you have to repeat the template<...> clause. 换句话说,您必须重复template<...>子句。 (Whether you use typename or class in the <...> is indifferent. Since it doesn't have to be a class, Most people I know prefer typename , since this corresponds closer to what is meant.) (无论您在<...>使用typename还是class都是无关紧要的。由于它不必是类,所以我认识的大多数人都喜欢typename ,因为它更接近于它的含义。)

As for keeping the implementation separate: templates in C++ are somewhat broken in this respect. 至于将实现分开:C ++中的模板在这方面有些破损。 You can't avoid the compiler dependency. 您无法避免编译器依赖性。 You still do want to keep the implementation separate from the definition, however. 但是,您仍然希望将实现与定义分开。 The usual technique is to put the template implementation in a separate file ( .tcc , for example), and include this from the header. 通常的技术是将模板实现放在单独的文件中(例如.tcc ),并.tcc文件中包含它。

Keeping the implementation of a template separate is not a trivial thing to do. 使模板的实现保持独立不是一件容易的事。

In general it cannot be done. 通常,这是无法完成的。 That is, it cannot be done where the templated parameters may be "anything". 也就是说,在模板化参数可能为“任何”的情况下,无法完成此操作。

For a specific limited subset of templated parameters it is possible to do, for example if you have a template like: 对于模板参数的特定有限子集,可以执行此操作,例如,如果您有如下模板:

template< bool B > class Foo;

You can then specify: 然后,您可以指定:

extern template class Foo<true>;
extern template class Foo<false>;

and this is called "instantiating" the templates, and specifying to the compiler that there are implementations for values true and false, implemented elsewhere. 这称为“实例化”模板,并向编译器指定存在在其他位置实现的值true和false的实现。

This can also be done where the templated parameters are types and are limited to a specific subset. 如果模板化参数是类型且限于特定子集,也可以执行此操作。

Within the compilation unit you then define the template implementations and then instantiate the templates once again using the same as above but without the word "extern". 然后,在编译单元中定义模板实现,然后使用与上面相同但没有单词“ extern”的方式再次实例化模板。

I have done this in production code in a case where you are creating a member function to set a parameter value for a database stored-procedure call where only a very limited subset of parameter types are permitted. 如果您正在创建成员函数来设置数据库存储过程调用的参数值(其中仅允许参数类型的非常有限的子集),那么我已经在生产代码中完成了此操作。 If your types are a very limited subset then go ahead and do the same if this helps decouple the code and hide a lot of implementation detail (in the case where the implementation is then done in a database, it is well worth doing). 如果您的类型是一个非常有限的子集,那么继续进行操作,如果这有助于解耦代码并隐藏许多实现细节(那么在数据库中完成实现的话,那是非常值得的)。

There is an "in-between" ground where you provide the implementation in another header, often I have seen _i.h or similar for this convention and then you instantiate the templates in ones, including this header only when necessary. 有一个“介于两者之间”的基础,您可以在另一个标头中提供实现,通常我会看到_i.h或类似的约定,然后才在实例中实例化模板(包括此标头)。 Thus if you create a class Foo then in the header use the "extern" declaration for my foo class in Foo.h and in Foo.cpp , #include the _i.h file for the implementation and the instantiation. 因此,如果您创建了一个Foo类,则在标头中为Foo.hFoo.cpp foo类使用“ extern”声明, #include _i.h文件用于实现和实例化。

As for the syntax, in the template implementation file use: 至于语法,在模板实现文件中使用:

template<class Loc, class T>
LocTree<Loc,T>::method(...)
{
  ...
}

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

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