【问题标题】:Minor question regarding templeted functions in templated class关于模板类中模板函数的小问题
【发布时间】:2009-03-18 23:40:21
【问题描述】:

我正在尝试理解一些 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&lt;class T, class U&gt;.

【问题讨论】:

  • 不是一个拷贝构造函数。如果您尝试按值传递 Foo&lt;T&gt; 类,编译器会报错。

标签: c++ templates


【解决方案1】:

第一个模板(带有参数 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 作为参数的构造函数:转换构造函数......这很难预测。

【讨论】:

  • 希望从 Foo 隐式构造 Foo 可能是有正当理由的,但你说得对,那时它并不是真正的复制构造函数。
  • 实际上,在我的实际代码中,我有 Foo 和 Foo 类型的构造函数,但这一点很好理解。我很高兴编译器可以解决这些问题..
  • 是的,这是必要的,因为正如 T. McHenry 所说,在某些情况下您想要这种行为。例如,当您想管理多种类型的数字类型时,最好将成员函数模板化为所有类型只有一个定义,而忽略它是类还是基本类型。
  • 想象 shared_ptr 只要 U* 转换为 T* 就允许从 shared_ptr 构造
  • 我建议编辑:“...与类型一样多的复制构造函数...”并从该行中删除“复制”。正如您稍后指出的,这绝不是一个复制构造函数——即使他留下了这个构造函数,他也应该添加您拥有的版本。
【解决方案2】:

对于涉及的每个模板,它必须有单独的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 的(可能意外声明但未使用的)第二个参数。

【讨论】:

    猜你喜欢
    • 2019-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-28
    • 1970-01-01
    相关资源
    最近更新 更多