【问题标题】:Why we need the template keyword in C++?为什么我们需要 C++ 中的模板关键字?
【发布时间】:2012-05-25 06:03:30
【问题描述】:

一个函数模板:

template<class T> T 
max(T a, T b){return (a > b)? a: b;}

使用时:

max<int>(a, b); // Yeah, the "<int>" is optional most of the time.

但是如果你允许,我们可以这样写模板:

T max<class T>(T a, T b){return (a > b)? a: b;} 
//I know the return type T is not in its scope, don't focus on that.

因此,我们可以像普通函数一样维护相同形式的声明和使用。甚至不需要引入和键入关键字“模板”。我认为类模板会是一样的吗?那么是不是还有什么其他的原因让模板变成了我们今天所知道的形式呢?

我更改了表单,以便您不必关注返回类型:

auto max<class T>(T a, T b) -> T {return (a > b)? a: b;}
//This is C++11 only and ugly i guess. 
//The type deduce happens at compile time 
//means that return type really didn't to be a problem.

【问题讨论】:

  • 这只是选择的语法。我相信这背后没有真正的令人信服的理由。这只是一个简单的决定。
  • 当他们接受 c++11 时,您已经晚了几个月。现在你必须等待下一个 20 年。
  • 我不记得在 Design and Evolution of C++ 中检查过这样的变体,这是 AFAIK 为当时决定的事情(大约 20 年以前)。
  • 问答网站不是主观问题的好格式。但是,您并不是唯一一个要求这样做的人。 David Abrahams(MPL 背后的人)有一篇有趣的博客文章,介绍了模板代码的更短语法:cpp-next.com/archive/2011/11/having-it-all-pythy-syntax 他甚至在 clang 邮件列表上写过关于它的文章,并请求帮助将解析器/语义分析更改为尝试这种语法并检查它是否会引起歧义等:)
  • @MatthieuM。知道原因会更好。有时我不明白为什么我们需要声明(许多语言不需要)但是当我得到答案时,它的目标是帮助不打扰我在编码时心情更好,并且更好地知道如何写好代码。

标签: c++ templates syntax language-lawyer


【解决方案1】:

我想到的直接答案是:
仅仅因为提出模板提案的人这么说,而标准委员会中没有人认为输入这些额外的8 字符会造成开销。

换个说法:
模板的语法一开始就复杂且令人生畏,确保关键字template 的存在使代码读者更直观地知道他们正在处理模板,而不是 C++ 或任何实现提供的任何其他野兽特定构造(读取编译器扩展)。

【讨论】:

    【解决方案2】:

    你必须在使用它之前声明T,所以它真的必须

    <class T> T max(T a, T b){return (a > b)? a: b;} 
    

    但是不清楚&lt;class T&gt; 是什么——编译器很可能会对此感到困惑。前面的template 清楚地表明&lt; 不是运算符,而是包含类型声明的大括号。

    从这个角度来看,您的第二个示例应该是可行的,但请记住,这种语法仅适用于 C++11,并且模板是更早引入的。

    【讨论】:

    • 有些语言根本不需要template&lt;class T&gt;,而且完全没问题。
    • Scala、Rust。有很多,只是不记得了。这绝对是不是必须的。顺便说一句,在 C++ 中,有时可以在声明之前使用标识符(考虑相互调用的内联类方法:它们不需要前向声明),所以即使对于 C++,“必须先声明 T”听起来像理由不充分。
    • 很好的观察,但我认为这些是 C++ 中的例外。一般来说,我认为您必须在访问之前声明,至少在 C++ 中。其他语言当然不受此限制。
    • @cschwan 使函数作为一个整体就像类一样没有害处。在使用之前声明只是一种确保不会意外引入新名称的方法(例如拼写错误或拼写错误或其他任何东西),这种语法不会违反规则。
    【解决方案3】:

    我相信问题在于编译器实现的简单性:C++ 中使用的任何名称都必须至少在用于帮助编译器能够从头开始解析之前声明(原因我不知道)。这就是你有奇怪的新语法来声明函数的原因之一,它允许在参数之后定义返回类型。

    所以这里的原因是,阅读您的示例,T 是使用的第一个名称,但它之前没有声明,因此编译器不知道它是什么或它在什么样的表达式中。

    【讨论】:

      【解决方案4】:

      您很快就会使用这种方法解析问题:

      template <typename> int f(); // Current declaration syntax, type template argument.
      template <int> int f();      // Current declaration syntax, non-type template argument.
      
      void f<class>(); // New declaration syntax, type argument. 
      void f<int>(); // New declaration syntax, non-type argument.
      (void) f<int>(); // (void) is a cast , f is instantiation of f<class> with type int.
      

      【讨论】:

      • 这不是问题。 (void) f&lt;int&gt;(); 将被视为与 template&lt;int&gt; void f(); 相同,如果它是单独的。并且在用作右值时将被视为强制转换。正常功能也会出现同样的问题。
      • @Mike:尝试让解析完全明确。 f&lt;int&gt; f&lt;int&gt; (); 呢? f&lt;int&gt; (*f&lt;int&gt;) (); ? (f&lt;int&gt;*) (*f&lt;int&gt;) (); ?
      • f&lt;int&gt; 将是我认为的预定义类型,因为它的右侧没有括号。我不确定类名和函数名是否可以重载。如果允许,它将是与template&lt;int&gt; f&lt;int&gt; f(); 相同的函数模板,第二个将是指向第一个的指针,第三个与第二个相同,只是它们单独时返回类型不同.而且没有办法让其中任何一个成为演员。
      猜你喜欢
      • 2020-05-20
      • 2014-05-29
      • 2016-07-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多