很难说清楚这一点。有时我会看到这样的课程:
template <typename T>
class Wrapper
{
public:
Wrapper(const T& t) : t_(t) {}
Wrapper(const Wrapper& w) : t_(w.t_) {}
private:
T t_;
}
据我所知,这是合法的代码。但是,为什么允许复制构造函数接受const Wrapper&
而不明确声明它需要const Wrapper<T>&
。什么时候隐含的模板类型?如果不使用类内定义,是否允许以这种方式编写复制构造函数?
答案 0 :(得分:3)
基本上,在类模板定义中,您可以使用 template-name 将模板定义为 template-id的完整参数化版本的简写
答案 1 :(得分:3)
它由14.6.1 / 1中的语言标准明确指定:
在类模板的范围内, 当模板的名称是 既不合格也不跟随&lt; 它相当于的名称 模板后面跟着 模板参数包含在&lt;&gt;。
中
这是在标准的后续版本中重新措辞(通过“注入类名”的概念),但重点是文档中明确说明了这种行为。
要回答问题的第二部分,此规则在编写类外方法定义时也适用于参数声明,但它不适用于返回类型声明。例如,此代码正常
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 !!!
P.S。最后一项声明需要进一步研究。 Comeau Online编译器认为这是一个错误,而GCC认为它是可以的。我稍后会回来。
P.P.S。 MSVC ++ 2005中的编译器抱怨后一个声明带有警告
warning C4812: obsolete declaration style: please use 'Wrapper<T>::Wrapper' instead
...有趣
答案 2 :(得分:0)
在这样的模板化类中,使用类的名称与使用Wrapper<T>
相同。
答案 3 :(得分:0)
不,你不得不写下课:
template <typename T>
Wrapper<T>::Wrapper<T>(const Wrapper<T>& w) : t(w.t) {}
但在课堂上,Wrapper
代表“当前班级”。
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
}