C++模板友元运算符重载
我的代码有什么问题吗?
template<int E, int F>
class Float
{
friend Float<E, F> operator+ (const Float<E, F> &lhs, const Float<E, F> &rhs);
};
G++ 只是不断发出警告:
float.h:7: warning:friend statements 'Float
float.h:7: warning: (如果这不是什么您想要的,请确保函数模板已被声明,并在此处的函数名称后添加 <>) -Wno-non-template-friend 禁用此警告
我尝试添加 <>正如警告注释中提到的,在此处的函数名称
之后,但 g++ 给了我一个错误。
我用 clang++ 编译了代码,很好,没有任何警告。
What is wrong with my code?
template<int E, int F>
class Float
{
friend Float<E, F> operator+ (const Float<E, F> &lhs, const Float<E, F> &rhs);
};
G++ just keeps warning:
float.h:7: warning: friend declaration ‘Float<E, F> operator+(const Float<E, F>&, const Float<E, F>&)’ declares a non-template function
float.h:7: warning: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here) -Wno-non-template-friend disables this warning
I tried to add <> after the function name here
as mentioned in the warning note, but g++ gives me an error.
I compiled the code with clang++, it was fine, no warning at all.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您需要完全按照警告所述进行操作:
这声明了运算符模板的完全特化,是类模板的特定实例的友元。在对问题的评论中,UncleBens 善意地提供了一个解释链接为什么这么复杂。
You need to do exactly as the warnings say:
This declares a full specialization of the operator template a friend of a specific instance of the class template. In a comment to the question UncleBens has kindly provided a link to an explanation why that is so complicated.
这只是关于该语言的一个棘手方面的警告。当您声明
friend
函数时,它不是声明所在类的成员。为了方便起见,您可以在那里定义它,但它实际上属于命名空间。在类模板内声明一个不是模板的友元函数,仍然在命名空间中声明一个非模板函数。它既不是类的成员,也不是模板。但是,它是由类模板生成的。
从模板生成非模板函数有点模糊。例如,您不能在
class
块之外添加该函数的声明。因此,您也必须在class
块内定义它,这是有意义的,因为类模板将生成它。朋友们另一个棘手的事情是,
class Float {}
内部的声明并没有声明命名空间中的函数。您只能通过参数相关的意义重载解析来找到它,即指定参数的类型为Float
(或引用或指针)。对于operator+
来说这不是问题,因为无论如何它都可能被重载,并且除了用户定义的类型之外永远不会被调用。作为潜在问题的示例,假设您有一个转换构造函数
Float::Float( Bignum const& )
。但是Bignum
没有operator+
。 (抱歉,这是一个人为的示例。)您希望依靠operator+(Float const&, Float const&)
进行Bignum
加法。现在,my_bignum + 3
将无法编译,因为两个操作数都不是Float
,因此它无法找到friend
函数。也许,您无需担心,只要相关函数是
运算符
即可。或者,您也可以将
friend
更改为模板。在这种情况下,它必须在class {}
块外部定义,并在其之前声明,而不是需要在内部声明和定义。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.
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 theclass
block as well, which makes sense because the class template will generate it.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 typeFloat
(or a reference or pointer). This is not an issue foroperator+
, as it is likely to be overloaded anyway, and it will never be called except for with user-defined types.For an example of a potential issue, imagine you have a conversion constructor
Float::Float( Bignum const& )
. ButBignum
does not haveoperator+
. (Sorry, contrived example.) You want to rely onoperator+(Float const&, Float const&)
forBignum
addition. Nowmy_bignum + 3
will not compile because neither operand is aFloat
so it cannot find thefriend
function.Probably, you have nothing to worry about, as long as the function in question is an
operator
.Or, you can change the
friend
to be a template as well. In that case, it must be defined outside theclass {}
block, and declared before it, instead of needing to be declared and defined inside.这是一个相当古老的主题,但我认为声明运算符的最简单方法是在 Float 类中定义它。
语法更容易编写和理解,并且它的工作方式完全相同(除了它将被内联),它不会是一个成员函数。
This is quite an old topic but I think the easiest way to declare the operator is to define it inside Float class.
The syntax is easier to write and understand and it will work exactly the same (except that it will be inlined), it will no be a member function.