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

发布于 2024-09-28 19:07:22 字数 614 浏览 2 评论 0原文

我的代码有什么问题吗?

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; operator+(const Float&, const 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

烂柯人 2024-10-05 19:07:23

您需要完全按照警告所述进行操作:

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

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

这声明了运算符模板的完全特化,是类模板的特定实例的友元。在对问题的评论中,UncleBens 善意地提供了一个解释链接为什么这么复杂。

You need to do exactly as the warnings say:

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

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

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.

荒人说梦 2024-10-05 19:07:22

这只是关于该语言的一个棘手方面的警告。当您声明 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 {}外部定义,并在其之前声明,而不是需要在内部声明和定义。

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);
};

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 the class 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 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.

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.

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 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);
};
暗藏城府 2024-10-05 19:07:22

这是一个相当古老的主题,但我认为声明运算符的最简单方法是在 Float 类中定义它。

template<int E, int F>
class Float
{
public:
    friend Float operator+ (const Float &lhs, const Float &rhs)
    {
        // Whatever you need to do.
    }
};

语法更容易编写和理解,并且它的工作方式完全相同(除了它将被内联),它不会是一个成员函数。

MSDN:在类声明中定义的友元函数不被视为在封闭类的范围内;它们在文件范围内。

This is quite an old topic but I think the easiest way to declare the operator is to define it inside Float class.

template<int E, int F>
class Float
{
public:
    friend Float operator+ (const Float &lhs, const Float &rhs)
    {
        // Whatever you need to do.
    }
};

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.

MSDN: Friend functions defined inside class declarations are not considered in the scope of the enclosing class; they are in file scope.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文