C++ template friend operator overloading

2019-01-13 19:25发布

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.

3条回答
2楼-- · 2019-01-13 20:00

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.

查看更多
成全新的幸福
3楼-- · 2019-01-13 20:08

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);
};
查看更多
混吃等死
4楼-- · 2019-01-13 20:09

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.

查看更多
登录 后发表回答