正确的朋友模板函数语法

Correct syntax for friend template function

本文关键字:函数 语法 朋友      更新时间:2023-10-16

在C 编程语言中,第四版 - 第23.4.7章朋友,我找到了以下示例(我对其进行了稍作修改以显示相关部分):

template<typename T>
class Vector {
public:
    friend Vector operator*<>(const Vector& v, int f); 
                           ^^ ~~~~ ?
};
template<typename T>
Vector<T> operator*(const Vector<T>& v, int f) {
    return v;
}

我尝试编译它,但是我会得到以下错误(clang):

main.cpp:8:20: error: friends can only be classes or functions
        friend Vector operator*<>(const Vector& v, int f); 
                      ^
main.cpp:8:29: error: expected ';' at end of declaration list
        friend Vector operator*<>(const Vector& v, int f); 
                               ^
                               ;
2 errors generated.

书籍解释:

&lt;>需要在朋友函数的名称之后清楚地表明朋友是模板函数。如果没有&lt;>,将假设一个非模板函数。

就是这样。

没有<>,此代码编译,但是当使用操作员*时(例如: Vector<int> v; v*12;),则会出现链接器错误:

main.cpp:(.text+0xb): undefined reference to `operator*(Vector<int> const&, int)'

因此,我认为需要<>告诉编译器,每次为给定类型实例化矢量模板应生成操作员*的功能模板。

但是我在书中的示例中做错了什么,为什么?

正如书所说的,

需要<>在需要朋友函数的名称之后清楚地表明朋友是模板函数。

这意味着,名称应参考函数模板,该函数模板应提前声明(作为模板)。例如

// forward declaration of the class template
template<typename T>
class Vector;
// declaration of the function template
template<typename T>
Vector<T> operator*(const Vector<T>& v, int f);
template<typename T>
class Vector {
public:
    // friend declaration
    friend Vector operator*<>(const Vector& v, int f); 
};
// definition of the function template
template<typename T>
Vector<T> operator*(const Vector<T>& v, int f) {
    return v;
}

在您的情况下,您直接在 Vector中直接将 operator*声明为朋友,而没有任何先前的声明。因此,正确的语法是:

template<typename T>
class Vector {
public:
    template<typename>
    friend Vector operator*(const Vector& v, int f);               
};
template<typename T>
Vector<T> operator*(const Vector<T>& v, int f) {
    return v;
}

wandbox上的实时示例

要使模板朋友方法语法工作您需要此模板方法的前向声明。

template<typename T>
class Vector;
template<typename T>
Vector<T> operator*(const Vector<T>& v, int f);
template<typename T>
class Vector
{
    template<typename T_> friend
    Vector<T_> operator*(const Vector<T_>& v, int f);
};
template<typename T>
Vector<T> operator*(const Vector<T>& v, int f)
{
    return v;
}

您使用的任何书都错误地解释了它。

您需要做的是

template<typename T>
class Vector
{
       public:
           friend Vector<T> operator*(const Vector<T>& v, int f); 
};
template<typename T>
   Vector<T> operator*(const Vector<T>& v, int f)
{
    return v;
}

以上使operator*()接受Vector<T>Vector<T>的朋友,而不是Vector<U>的朋友(除非TU相同的类型)。

在类定义中,可以从Vector<T>中忽略<T>,但是根据我的经验,人类似乎在说服自己的函数声明和功能定义相互对应时遇到了更多麻烦。所以我通常更喜欢不这样做。...

明确专门化模板时使用<>语法,但这不是您要做的。例如,具有模板函数;

 template <class T> void foo(T) { /* whatever */   }
 template<> void foo<int> {/* something specific to int */ }

使用<>也是C FAQ建议的。

,但是您可以像静态的那样简单地使用模板声明来解决它,只是必须以与类参数不同的参数命名。然后,在单独的定义中,您可以再次使用任何类型名称:

template <typename T>
class Vector {
 public:
  T i{};
  // Typename must be different from the class typename(s).
  template <typename T_1>
  friend ostream& operator<<(ostream& os, const Vector<T_1>& v);
};
// Typename can be any.
template <typename T>
ostream& operator<<(ostream& os, const Vector<T>& v) {
  return os << v.i;
}

实时演示

仅此而已。无需怪异的 <>在函数声明之间或预定前。