【问题标题】:C++ template friend operator overloadingC++ 模板友元运算符重载
【发布时间】:2011-04-28 17:29:26
【问题描述】:

我的代码有什么问题?

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 declaration ‘Float&lt;E, F&gt; operator+(const Float&lt;E, F&gt;&amp;, const Float&lt;E, F&gt;&amp;)’ 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 &lt;&gt; after the function name here) -Wno-non-template-friend disables this warning

我尝试add &lt;&gt; after the function name here,如警告说明中所述,但 g++ 给了我一个错误。

我用clang++编译了代码,很好,一点警告都没有。

【问题讨论】:

标签: c++ templates operator-overloading friend


【解决方案1】:

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

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

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

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

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

或许,您无需担心,只要有问题的函数是 operator

或者,您也可以将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);
};

【讨论】:

  • 你不应该在定义operator+模板之前也转发声明Float类吗?
  • @ValerioFormato 是的;我没有把它包括在内,因为考虑到他的问题,子飞肯定已经这样做了。
【解决方案2】:

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

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

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

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

【讨论】:

  • 不行,在operator +的情况下,一般最简单最好的方式是先实现operator +=为会员,再以非会员非好友的方式实现operator ++=。这可确保您定义了两个运算符并且它们的行为一致。
【解决方案3】:

你需要完全按照警告说的去做:

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 问题的评论中,请提供a link to an explanation 为什么这如此复杂。

【讨论】:

  • @Potatoswatter:朋友声明声明了一个特定的专业化类的朋友,不是吗?
  • 实际上,我刚刚测试了@sbi 的代码,它适用于我的g++。
  • @Zifei:这个sn-p可以,但是需要改函数的定义。 (抱歉,我没有注意到函数形式的变化。)
猜你喜欢
  • 2011-05-08
  • 1970-01-01
  • 2021-05-18
  • 2011-06-07
  • 2010-11-20
  • 1970-01-01
相关资源
最近更新 更多