C++ 模板友元运算符重载

我的代码有什么问题?

template<int E, int F>
class Float
{
 friend Float<E, F> operator+ (const Float<E, F> &lhs, const Float<E, F> &rhs);
};

G++ 只是不断警告:

G++ just keeps warning:

float.h:7: 警告:友元声明‘Floatoperator+(const Float&, const Float&)' 声明了一个非模板函数

float.h:7: 警告:(如果这不是您想要的,请确保已经声明了函数模板,并在此处的函数名称后添加 <>)-Wno-non-template-friend 禁用此警告

我试图添加<>在警告说明中提到的函数名称之后,但是 g++ 给了我一个错误.

I tried to add <> after the function name here as mentioned in the warning note, but g++ gives me an error.

我用clang++编译了代码,很好,完全没有警告.

I compiled the code with clang++, it was fine, no warning at all.

推荐答案

这只是关于语言的一个棘手方面的警告.当你声明一个 friend 函数时,它不是声明所在类的成员.为了方便你可以在那里定义它,但它实际上属于命名空间.

It's just a warning about a tricky aspect of the language. When you declare a friend function, it is not a member of the class the declaration is in. You can define it there for convenience, but it actually belongs to the namespace.

在类模板中声明一个不是模板的友元函数,仍然在命名空间中声明了一个非模板函数.它既不是类的成员,也不是模板.但是,它是由类模板生成的.

Declaring a friend function which is not a template, inside a class template, still declares a non-template function in the namespace. It is neither a member of the class, nor itself a template. However, it is generated by the class template.

从模板生成非模板函数有点模糊.例如,您不能在 class 块之外为该函数添加声明.因此,您还必须在 class 块中定义它,这是有道理的,因为类模板会生成它.

Generating non-template functions from a template is a bit hazy. For example, you cannot add a declaration for that function outside the class block. Therefore you must define it inside the class block as well, which makes sense because the class template will generate it.

关于朋友的另一个棘手的事情是class Float {} 中的声明没有在命名空间中声明函数.您只能通过依赖于参数的含义重载解析来找到它,即指定参数具有 Float 类型(或引用或指针).这对于 operator+ 来说不是问题,因为无论如何它都可能被重载,并且除了用户定义的类型之外永远不会调用它.

Another tricky thing about friends is that the declaration inside class Float {} does not declare the function in the namespace. You can only find it through argument-dependent meaning overload resolution, i.e. specifying an that an argument has type Float (or a reference or pointer). This is not an issue for operator+, as it is likely to be overloaded anyway, and it will never be called except for with user-defined types.

举一个潜在问题的例子,假设你有一个转换构造函数Float::Float(Bignum const&).但是Bignum 没有operator+.(对不起,人为的例子.)您想依靠 operator+(Float const&, Float const&) 来进行 Bignum 加法.现在 my_bignum + 3 将无法编译,因为两个操作数都不是 Float,所以它找不到 friend 函数.

For an example of a potential issue, imagine you have a conversion constructor Float::Float( Bignum const& ). But Bignum does not have operator+. (Sorry, contrived example.) You want to rely on operator+(Float const&, Float const&) for Bignum addition. Now my_bignum + 3 will not compile because neither operand is a Float so it cannot find the friend function.

也许,您无需担心,只要所讨论的函数是 operator.

Probably, you have nothing to worry about, as long as the function in question is an operator.

或者,您也可以将 friend 更改为模板.在这种情况下,它必须在 class {} 块的外部定义,并在它之前声明,而不需要在内部声明和定义.

Or, you can change the friend to be a template as well. In that case, it must be defined outside the class {} block, and declared before it, instead of needing to be declared and defined inside.

template<int E, int F> // now this is a template!
Float<E, F> operator+ (const Float<E, F> &lhs, const Float<E, F> &rhs);

template<int E, int F>
class Float
{
  // deduce arguments E and F - this names operator+< E, F >.
 friend Float<E, F> operator+<> (const Float<E, F> &lhs, const Float<E, F> &rhs);
};

相关文章