【问题标题】:What is the rationale behind the syntax chosen to declare template friends?选择声明模板朋友的语法背后的基本原理是什么?
【发布时间】:2011-07-23 20:24:23
【问题描述】:

声明模板函数友元涉及一些非常不直观的语法,即使对于 C++ 也是如此!为所需的额外<> 选择语法的理由是什么?使用template 关键字不是更有意义吗?

对于那些不知道的人,这里有一个你可以尝试做的例子:

template <typename T>
class Foo
{
  int x;
  friend void bar(Foo<T>);
};

template <typename T>
void bar(Foo<T> f)
{
  std::cout << f.x;
}

如果你尝试调用bar(Foo&lt;T&gt;()),你会得到链接器错误。

要解决这个问题,您必须转发声明 bar(因此是 Foo),然后在朋友声明中粘贴一个奇怪的 &lt;&gt;

template <typename T> class Foo;
template <typename T> void bar(Foo<T>);

template <typename T>
class Foo
{
  int x;
  friend void bar<>(Foo<T>); // note the <> (!?)
};

template <typename T>
void bar(Foo<T> f)
{
    std::cout << f.x;
}

我的问题是,&lt;&gt; 语法背后的基本原理是什么?使用template 关键字或类似的东西不是更直观吗?

编辑:澄清一下,我已经知道 为什么 是必需的,我想知道的是为什么他们选择使用 来消除歧义,而不是使用其他更直观的方法语法。

【问题讨论】:

  • +1 我一直在想这个问题。在“Effective C++”中有关于这个的讨论,但我不太明白。
  • 我希望这个不直观的东西在 c++11 中变得直观
  • @Hades:除非我错过了,否则 C++11 在这方面没有任何改变。

标签: c++ templates syntax friend


【解决方案1】:

等等。您没有声明朋友模板。您将模板的专业化声明为朋友!因此,为什么要在其中放置 template 子句?

命名函数模板特化的语法是teplateName&lt;ArgumentList&gt;,这就是你应该根据标准在友元声明中使用的语法。

如果您想与整个模板以及生成的所有特化和显式特化交朋友,您仍然可以这样做,然后您可以使用模板子句

template<typename U>
friend void bar(Foo<U>);

【讨论】:

  • 如果语法基于专业化,那么为什么不是语法:template &lt;&gt; friend void bar&lt;T&gt;(Foo&lt;T&gt;);?为什么我放了一个没有模板关键字的空模板参数列表?
  • @Peter 好吧,template&lt;&gt; friend void bar&lt;T&gt;(Foo&lt;T&gt;); 在我看来就像一个显式特化(template&lt;&gt; 仅用于声明显式特化)。但是您在问题中编写的朋友声明不需要模板的明确专业化存在。它还与模板的实例化友好。我可以想象这是不使用template&lt;&gt; 的理由——人们可能会误以为它会声明一个明确的专业化。
  • @Peter 也许我应该澄清一下,当我说“您将模板的专业化声明为朋友”时,我使用标准定义“专业化”的术语来表示。不是大多数 C++ 开发人员使用它的目的。有生成的特化,编译器通过实例化模板为您创建。并且有程序员创建的显式特化,并且不需要进行实例化。我对这个词的使用没有特别指定这两种中的任何一种。在声明中使用 template&lt;&gt; 会引入显式特化。
  • 我明白你的意思,但我仍然不相信选择的语法是最直观的:-) 为什么不friend template void bar(Foo&lt;T&gt;);
  • @Peter template&lt;typename T&gt; void f(T) { } void f(int) { }。要调用模板,您需要说f&lt;&gt;(0)。否则它将调用非模板。另一个:struct A { template&lt;typename T&gt; void f(T); void f(int); }; template&lt;&gt; void A::f(int);。这段代码格式错误(虽然被 GCC 和 Clang 接受,但他们确实允许在这里使用非法代码。Comeau 严格拒绝这一点)。要引用成员模板并对其进行专门化,您需要说A::f&lt;&gt;(int)
【解决方案2】:

引用this page:

调用非模板函数是因为非模板函数在重载决议中具有优先权。

所以我猜friend void bar&lt;&gt;(Foo&lt;T&gt;); 很直观,因为您要确保它是您正在调用的模板函数,而不是Foo&lt;T&gt; 的重载。否则编译器将无法注意到模板化或非模板化函数是类的朋友。

我不清楚为什么使用&lt;&gt; 语法而不是template 语法。

【讨论】:

  • 谢谢,但这是我想知道的关于 &lt;&gt;template 的部分:-)
  • @Peter Alexander:啊,但我现在把我的答案留在里面,它可能会激发比我更了解 C++ 的人的真正答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-28
  • 2017-03-09
  • 1970-01-01
  • 1970-01-01
  • 2014-07-23
相关资源
最近更新 更多