2010-01-20 95 views
8

定义类声明内部的模板类的成员函数与外部的区别?在类内部和外部定义的模板类的成员函数之间的区别

定义内:

template <typename T> 
class A 
{ 
public: 
    void method() 
    { 
     //... 
    } 
}; 

定义外:

template <typename T> 
class B 
{ 
public: 
    void method(); 
}; 

template <typename T> 
void B<T>::method() 
{ 
    //... 
} 

对于非模板类,这是内联和非内联方法之间的差别。模板类也是如此吗?

我的大多数同事的默认设置是在类内提供定义,但我一直喜欢在类之外定义。我的意愿是否合理?

编辑:请假设所有上述代码都在类的头文件中提供。

+0

我从来没有见过任何引用表明在类声明中定义方法主体使内联方法。我错过了什么吗? – Dathan 2010-01-20 17:53:15

+0

@Dathan: 请看这里:http://www.parashift.com/c++-faq-lite/inline-functions.html#faq-9.8 在这里:http://msdn.microsoft.com/en-us /library/bw1hbe6y%28VS.80%29.aspx – Ben 2010-01-20 17:56:42

+3

@Dathan:你已经缺少C++标准的§9.3/ 2,它说:“一个成员函数可以在它的类定义中定义(8.4),其中它是一个内联成员函数......“编辑:另请注意,这是一个类定义 - 类声明是类似于:'class x;' – 2010-01-20 17:58:01

回答

2

是的,完全相同的是模板类如此。

模板类的方法定义通常首选内联的原因是,对于模板,实例化模板时整个定义必须可见。

所以如果你把函数定义放在一些单独的.cpp文件中,你会得到一个链接错误。 唯一的一般解决方案是通过在类内部或外部使用inline关键字定义函数来使函数内联。但在任一情况下,它必须是可见的任何地方被调用的函数,这意味着它通常必须在相同的标头,如在类定义。

+0

只是出于好奇,链接器错误现在普遍成立吗?我在过去知道一些编译器提供了不同的模板实例化选项,例如,SGI Irix CC编译器默认为链接时实例化,实际上似乎鼓励将模板函数定义放在它们自己的.cpp文件中(即不在标题中,非内联,不可见调用代码,就像任何其他的非内联函数定义一样)只是想知道内联模板函数定义是否已经从编译器偏好变为语言的要求 – Darryl 2010-01-20 18:37:18

+0

@Darryl,你正在描述extern模板。标准扩展,并不是所有的编译器都支持它。新的标准C++ 1x增加了'extern'模板,尽管I bel即使它需要关键字。 – greyfade 2010-01-20 18:49:57

+0

模板在使用该特定实例的每个编译单元中编译,但它们是'弱'符号(gcc术语,我不知道标准是多么标准),并且在多个编译单元中定义了相同的符号不是一个链接错误。因此,不需要将“内联”添加到模板函数/方法。另一种说法是'inline'是编译器的一个提示,但它可以被编译器忽略(但它会影响符号的创建方式,以便链接器不会抱怨双重定义)。 – 2010-01-20 19:45:24

1

除了输入更多信息之外,没有区别。这包括template一下,inline具有参照类时多采用“精心制作”的名字。例如

template <typename T> class A { 
    A method(A a) { 
    // whatever 
    } 
}; 

template <typename T> inline A<T> A<T>::method(A a) { 
    // whatever 
} 

注意,当方法中定义指A<T>时,你总是可以省略模板参数列表<T>,只是使用A。在外部定义时,必须在返回类型和方法名称中使用“完整”名称(但不能在参数列表中)。

+0

你在这两种情况下都使用了“方法”,如果函数体很大,这可能很糟糕。这就是我想要避免的。 – Ben 2010-01-20 18:14:41

+2

** inline **关键字与实际优化代码较少有关,更多关于是否允许多个相同函数的定义。如果在头文件中定义了一个函数(这对模板是不可避免的,或者在类声明中定义了函数的情况),并且多个编译单元包含该函数,那么链接程序最终将最终得到多个(相同的)相同的功能/方法。 ** inline **关键字(它应该隐含在模板中)告诉链接器它是OK的,否则它会是链接器错误。 – UncleBens 2010-01-20 18:22:29

+0

关键是Ben用一个模板你没有任何选择。它必须内联标记或模板不起作用。这是一些人不喜欢模板的原因之一。同样值得注意的是,编译器实际上并不需要内联它可以做任何喜欢背后的事情。 – Goz 2010-01-20 18:23:26

0

我知道这个..我认为它一定是一些什么帮助完整的你?

defining a member function outside of its template 

这也不行提供模板类的这样的一个成员函数的定义:

// This might be in a header file: 
template <typename T> 
class xyz { 
    void foo(); 
    }; 

// ...

// This might be later on in the header file: 
    void xyz<T>::foo() { 
// generic definition of foo() 
    } 

这是不对的几个原因。所以是这样的:

 void xyz<class T>::foo() { 
     // generic definition of foo() 
     } 

正确的定义需要template关键字和相同的模板参数,类模板的定义声明。这样得到:

 template <typename T> 
      void xyz<T>::foo() { 
      // generic definition of foo() 
       } 

注意,还有其他类型的模板指令,因为成员模板等这样的,每一个需要他们自己的形式。重要的是要知道你有什么,所以你知道如何写每种口味。这尤其是因为一些编译器的错误信息可能不清楚哪些是错误的。当然,获得一本好的和最新的书。

如果你有一个模板中的嵌套成员模板:

template <typename T> 
     struct xyz { 
     // ... 
     template <typename U> 
     struct abc; 
     // ... 
     }; 

你是如何定义的xyz以外ABC?这不起作用:

 template <typename U> 
    struct xyz::abc<U> { // Nope 
     // ... 
    }; 

也没有这样的:

template <typename T, typename U> 
struct xyz<T>::abc<U> { // Nope 
// ... 
}; 

你将不得不这样做:

 template <typename T> 
     template <typename U> 
      struct xyz<T>::abc { 
      // ... 
      }; 

注意它的...abc...abc<U>因为ABC是 “主”模板。 IOWs,这不好:

//这里不允许: 模板模板struct xyz :: abc {};

相关问题