关于模板化类中模板化函数的小问题

时间:2009-03-18 23:40:21

标签: c++ templates

我试图理解一些C ++语法:

template<class T>
class Foo 
{
   Foo();

   template<class U>
   Foo(const Foo<U>& other);
};

template<class T>
Foo<T>::Foo() { /*normal init*/ }

template<class T>
template<class U>
Foo<T>::Foo(const Foo<U>& other) { /*odd copy constructed Foo*/ }

所以,我编写了这样的代码,它恰好在windows和linux中编译。我不明白的是复制构造函数有两个模板定义的原因。基本上,在我找到正确的语法之前,我必须先解释一下,我想知道为什么特定的语法是正确的,而不是template<class T, class U>.

2 个答案:

答案 0 :(得分:7)

第一个模板(带参数T)表示是用参数T模板化的。

第二个模板(带参数U)表示模板化类(带参数T)的成员函数是用参数U模板化的 - 它是构造函数。

实际上,这里有一个模板类,它将生成与用作构造函数参数的类型一样多的复制构造函数。

在复制构造函数的特定情况下,您不应该这样做,而是:

template<class T>
class Foo 
{
   Foo();

   Foo(const Foo<T>& other);
};

template<class T>
Foo<T>::Foo() { /*normal init*/ }

template<class T>
Foo<T>::Foo(const Foo<T>& other) { /*odd copy constructed Foo*/ }

因为在你的例子中,它不是复制构造函数,而是将类型U作为参数的构造函数:转换构造函数......很难预测。

答案 1 :(得分:4)

每个涉及的模板都必须有单独的template子句。这里涉及两个模板,它们都应该得到它们的(非空)模板子句:

  • 班级模板Foo
  • 构造函数模板

考虑这个案例因为参数U所属的位置不明确而失败

template<typename T>
struct A {
    template<typename U> void f();
};

template<typename T, typename U>
void A<T>::f() { }

现在,参数U是怎么回事?当然编译器可能猜测它可能属于f,但猜测并不是编译器所喜欢的:)现有规则说,根据模板的嵌套,模板子句以正确的顺序出现。一切都很清楚了。

即使有人提出如何将参数与所涉及的模板的参数相匹配(到目前为止我没有看到真正的困难),它也会不一致。因为截至目前,一个模板子句列出了相应模板接受的所有参数。很像函数参数列表。如果我们将所有内容放在一个子句中,那么明确的语义就可以被打破 - 更不用说当我们再次将定义放入类中时,模板会突然得到它自己的子句:

// provides arguments for A's parameters, then for f ones 
// when it's called
A<int> a; 
a.f<bool>();

当我们有单独的模板子句来捕获每个自己的参数时,这是更自然的。所以,上面错误定义的语法是

template<typename T> 
 template<typename U>
void A<T>::f() { }

现在,代码的读者也会立即看到这是成员模板的定义,而不是A的(潜在意外声明但未使用的)第二个参数。