2

这很难说。有时我会看到这样的课程:

template <typename T>
class Wrapper
{
public:
    Wrapper(const T& t) : t_(t) {}
    Wrapper(const Wrapper& w) : t_(w.t_) {}
private:
    T t_;
}

据我所知,这是合法代码。但是,为什么允许复制构造函数接受 aconst Wrapper&而没有明确说明它需要 a const Wrapper<T>&。什么时候隐含模板类型?如果您不使用类内定义,是否允许以这种方式编写复制构造函数?

4

4 回答 4

3

基本上,在类模板定义中,您可以使用模板的模板名称 作为模板 ID的完整参数化版本的简写。

于 2009-11-09T22:29:08.447 回答
3

它由 14.6.1/1 中的语言标准明确指定:

在类模板的范围内,当模板名既没有限定也没有后跟<时,相当于模板名后跟<>中的模板参数。

这在标准的更高版本中被重新措辞(通过“注入的类名”的概念),但关键是这种行为在文档中明确说明。

要回答您问题的第二部分,此规则在编写类外方法定义时也适用于参数声明,但不适用于返回类型声明。比如这段代码就OK

template <typename T> struct S {
  S foo(S);
};

template <typename T> S<T> S<T>::foo(S s) {
  /* whatever */
}

但是您不能<T>从方法定义中的返回类型中删除该位。(并且您不能<T>从方法的限定名称中删除。)

至于具体的构造函数:你应该使用<T>类的全名(带),但你不应该<T>在构造函数本身的名称中使用。因此,在您的情况下,课外定义的最短形式是

template <typename T> Wrapper<T>::Wrapper(const Wrapper& w) : t_(w.t_)
{
}

请注意,<T>即使您想要,也不能将位添加到构造函数名称中

template <typename T> Wrapper<T>::Wrapper<T>(const Wrapper& w)
                                         ^ ERROR !!!

PS 最后一个说法需要进一步研究。Comeau Online 编译器认为这是一个错误,而 GCC 认为它是 OK 的。我稍后会回到它。

PPS MSVC++ 2005 中的编译器抱怨后一种声明并带有警告

warning C4812: obsolete declaration style: please use 'Wrapper<T>::Wrapper' instead

有趣的...

于 2009-11-09T22:40:37.893 回答
0

在这样的模板化类中,使用类的名称与使用Wrapper<T>.

于 2009-11-09T22:30:11.483 回答
0

不,课外你必须写:

template <typename T>
Wrapper<T>::Wrapper<T>(const Wrapper<T>& w) : t(w.t) {}

但是在类里面,Wrapper代表“当前类”。

编辑:这是为了 Andrew 和他对为什么编译器会拒绝构造函数的调查:

template <typename T>
class Foo {
public:
    Foo() {}
    Foo(const Foo& f);
};

template <typename T>
Foo<T>::Foo<T>(const Foo<T>& f) { }

int main(int argc, char** argv)
{
    Foo<int> f;
    Foo<int> g(f); // make sure the template is instantiated
}
于 2009-11-09T22:52:19.070 回答