I want to add a iterator class type for my vector class,and I declare some compare operator as friend function of iterator class.but it didnt complie correctly,I did forward declaration.
template<class object>class vector;
template<class object>
bool operator<(typename vector<object>::const_iterator& lhs, typename vector<object>::const_iterator& rhs);
template<class object>class vector {
protected:
//some member
public:
class const_iterator {
friend bool operator< <>(const_iterator& lhs, const_iterator& rhs);
friend bool operator> <>(const_iterator& lhs, const_iterator& rhs);
//...
};
};
compiler said no matching overloaded function found,I use vs2019.I guess something wrong with forward declaration.
and another question is,I notice some people use this form when declare friend function inside class.
class myclass{
friend void foo<T>(T t);
//...
}
but when declare a operator as friend it's different
friend bool operator< <>(const myclass& lhs, const myclass& rhs);
I wonder what's the difference between these two.
please help me,thanks a lot.
In your forward declaration
template<class object>
bool operator<(typename vector<object>::const_iterator&,
typename vector<object>::const_iterator&);
const_iterator is in the non-deduced context, i.e. the compiler will not be able to deduce int for object in the following call:
vector<int>::const_iterator c1;
vector<int>::const_iterator c2;
c1 < c2;
I can suggest two solutions.
The simplest one: omit your forward declarations and provide a definition for operator< inside the body of const_iterator:
friend bool operator<(const_iterator& lhs, const_iterator& rhs) {
... return ... ;
}
If you can't define operator< inside const_iterator, use CRTP to turn a non-deduced context into a deduced one:
template<class derived>
struct const_iterator_crtp {};
template<class derived>
bool operator<(const_iterator_crtp<derived>&,
const_iterator_crtp<derived>&);
template<class object>
struct vector {
struct const_iterator : const_iterator_crtp<const_iterator> {
using base = const_iterator_crtp<const_iterator>;
friend bool operator< <>(base&, base&);
private:
int priv;
};
};
template<class derived>
bool operator<(const_iterator_crtp<derived>& lhs,
const_iterator_crtp<derived>& rhs)
{
auto& l = static_cast<derived&>(lhs); // these static_cast's are safe
auto& r = static_cast<derived&>(rhs);
return l.priv < r.priv;
}
Is the operator< a function template in the first solution? Why we don't need a <> after operator<?
It is not a template. You don't need <> in this definition.
You forward declare a template first. Without <>, a friend declaration introduces a non-template function. A non-template function, even if it has the same name as template one (non-template and template functions can overload!), should be defined somewhere. You'll get a link error without such a definition. To override the default behavior and to refer to the function template that was forward declared earlier, you add <>.
Related
Based on the answer in Implicit conversion when overloading operators for template classes I was able to write the following code that works perfectly fine (simplified example):
namespace my_library {
template <typename T>
struct Number {
T n;
inline Number(T n) : n(n) { }
friend Number<T> operator+(const Number<T> &a, const Number<T> &b) {
return Number<T>(a.n + b.n);
}
};
}
int main() {
return (int) (4 + my_library::Number<double>(3)).n; // returns 7
}
All I want to do is make it so that operator+ is not inlined within the definition of Number (but stays in the header file) while everything still works the same way - see the expression in the main function. Note that it requires that the integer 4 gets implicitly converted to double and then to Number<double>. I followed a comment linking to Binary operator overloading on a templated class but that solution did not work - the overloaded operator is no longer matched. Is there any way to make this work and have the body of the operator outside the struct definition? (Without complicating the operator interface or adding more overloads - in those cases I'd rather just keep it inlined.)
You can do it like this:
template <typename T>
struct Number {
// ...
template <class U>
friend Number<U> operator+(const Number<U> &a, const Number<U> &b);
};
template <typename U>
Number<U> operator+(const Number<U> &a, const Number<U> &b) {
return Number<U>(a.n + b.n);
}
In this example, operator+ will be a friend of all Number specializations even when the types don't match. This might be a broader friendship than you intended, but is the simplest way to achieve your objective of moving the definition of operator+ outside the definition of Number. Note that when a friend is not defined inline, you lose the benefit of having it as a "hidden friend". (A hidden friend can only be found via argument-dependent lookup, which means that the compiler will typically not have to consider it as a candidate function in most cases where it is not intended to be used.)
If you want each specialization of operator+ to only be a friend of one particular Number specialization where the types match, it is more complicated. You have to forward-declare the operator+ template in order to prevent the friend declaration from declaring a non-template function, and you also have to forward-declare Number so that it can be used in the operator+ forward declaration:
template <typename T> struct Number;
template <typename T>
Number<T> operator+(const Number<T>&, const Number<T>&);
template <typename T>
struct Number {
// ...
friend Number<T> operator+<>(const Number<T>&, const Number<T>&);
};
template <typename T>
Number<T> operator+(const Number<T> &a, const Number<T> &b) {
return Number<T>(a.n + b.n);
}
I'm learning how to use templates and how to overload operators. I've managed to overload operator[], but I've encountered a problem with overloading operator+ and operator=. Here is my code:
template <class T>
class A
{
public:
//...
friend A<T>& A<T>::operator+ (A<T>&, const A<T>&);
friend A<T>& A<T>::operator= (A<T>&, const A<T>&);
};
template<class T> A<T>& A<T>::operator+ (A<T>& left, const A<T>& right)
{
//some functions
return left;
}
template<class T> A<T>& A<T>::operator= (A<T>& left, const A<T>& right)
{
//some functions
return left;
}
Whenver I try to compile, I get those errors:
'+': is not a member of 'A<T>'
'=': is not a member of 'A<T>'
'operator =' must be a non-static member
What am I doing wrong?
EDIT:
I've managed to update the code:
template <class T>
class A
{
public:
//...
A<T> operator+ (A<T>);
A<T> operator= (A<T>, const A<T>);
};
template<class T> A<T> A<T>::operator+ (A<T> right)
{
//some functions
return *this;
}
template<class T> A<T> operator= (A<T> right)
{
//some functions
return *this;
}
Looks like operator+ works now fine, but compiler gives this error:
'operator=' must be a non static member
Why is it a static member, and how can I fix it?
For starters assignment operators must be non-static member functions
From the C++ Standard (13.5.3 Assignment )
1 An assignment operator shall be implemented by a non-static member
function with exactly one parameter. Because a copy assignment
operator operator= is implicitly declared for a class if not declared
by the user (12.8), a base class assignment operator is always hidden
by the copy assignment operator of the derived class.
And secondly (11.3 Friends)
1 A friend of a class is a function or class that is given permission
to use the private and protected member names from the class. A class
specifies its friends, if any, by way of friend declarations. Such
declarations give special access rights to the friends, but they do
not make the nominated friends members of the befriending class.
Thus for example this definition
template<class T> A<T>& A<T>::operator+ (A<T>& left, const A<T>& right)
^^^^^
{
//some functions
return left;
}
is incorrect. At least you should remove A<T>:: because the operator is not a member of the class.
An operator that is implemented as a non-static member must accept only 1 input parameter, the right-hand operand. The left-hand operand is the this object that the operator is being called on.
An operator that is implemented as a static member or a non-member must accept 2 input parameter, the left-hand and right-hand operands.
Your operator= is declared as a non-static member with 2 input parameters, which is wrong.
Also, operator+ is meant to return a new object that is a copy of the two input objects added together. Do not return a reference to the object that the operator is being called on. Whereas operator= is meant to return a reference to the object that is being assigned to.
Try this:
template <class T>
class A
{
public:
//...
A<T> operator+(const A<T>&) const;
A<T>& operator=(const A<T>&);
};
template<class T> A<T> A<T>::operator+(const A<T>& right) const
{
A<T> result(*this);
//some functions to add right to result as needed...
return result;
}
template<class T> A<T>& A<T>::operator=(const A<T>& right)
{
// some functions to copy right into this...
return *this;
}
Looking into some code of a colleague of mine, I came accross the following:
friend bool operator==<>(ValueIter<Type> const &rhs, ValueIter<Type> const &lhs);
It is declared in a template class:
template<typename Type>
class ValueIter: public std::iterator<std::bidirectional_iterator_tag, Type>
Can someone tell me what the ==<> symbol indicates? I expect it has something to with the != operator.
It looks like two, the operator== that is a full template instantiation or specialisation <>.
I've seen only a few like this in the wild though.
Given the friend, the class is probably befriending the template operator.
If you are getting linker errors with it, see this answer for why.
Your question is incomplete.
Presumably, in some context within the code you are examining, there is a templated operator==() function.
Then within some class, a particular specialisation of that templated operator==() is being declared as a friend.
Without context that you haven't given (i.e. of the preceding template definition, or of the enclosing class definition) it is not possible to give a more specific answer. There are too many possibilities for what the template or relevant specialisations are.
With
template <typename T> class ValueIter;
template <typename T>
bool operator==(ValueIter<T> const &rhs, ValueIter<T> const &lhs);
Inside template <typename T> class ValueIter
friend bool operator==(ValueIter const &rhs, ValueIter const &lhs);
and friend bool operator==(ValueIter<T> const &rhs, ValueIter<T> const &lhs);
add friendship to a non template operator.
friend bool operator==<>(ValueIter const &rhs, ValueIter const &lhs);,
friend bool operator==<>(ValueIter<T> const &rhs, ValueIter<T> const
friend bool operator==<T>(ValueIter const &rhs, ValueIter const &lhs);,
friend bool operator==<T>(ValueIter<T> const &rhs, ValueIter<T> const
add friendship to the template operator (just for the type with match T)
template <typename U> friend bool operator==(ValueIter<U> const &rhs, ValueIter<U> const &lhs); add friendship to the template operator (for any type U (which may differ of T))
==<> is used in the second point and is really == <>.
I have a class template Foo<T>.
I'd like to implement a non-member function Bar that takes two Foos and returns a Foo. I want Bar to be a non-member because it will be more natural for callers to write Bar(f1, f2) than f1.Bar(f2). I also want Bar to be inline because the calculation is trivial and frequent.
template <typename T>
inline Foo<T> Bar(const Foo<T> &lhs, const Foo<T> &rhs) {
...
}
The trick is Bar needs access to Foo's private data. I'd prefer not to have accessors to the private data--there's no good reason to expose the private data to users. So I'd like to make Bar a friend of Foo.
template <typename T>
class Foo {
...
private:
T w, x, y, z;
friend Foo<T> Bar(const Foo<T> &lhs, const Foo<T> &rhs);
};
Here's where I run into trouble. The compiler complains:
The inline specifier cannot be used when a friend declaration refers to a specialization of a function template.
Is this rule imposed by the standard or is it specific to MSVC++?
Here's what I've tried:
Make Bar a const public member function, and then to declare a non-member version that simply returns lhs.Bar(rhs). This seems the least hacky solution.
Remove the inline hint, knowing that the compiler is going to decide about inlining regardless of the hint. Does this then run afoul of the one-definition rule? It will still have to be defined in a header file because it's a function template.
Declare the member function with a dummy template type:
template <typename T>
class Foo {
...
private:
T w, x, y, z;
// Note that this declaration doesn't actually use Dummy. It's just there to
// satisfy the compiler.
template <typename Dummy>
friend Foo<T> Bar(const Foo<T> &lhs, const Foo<T> &rhs);
};
I'm not entirely sure why that works, but it does satisfy the compiler.
Is there a better solution?
If the calculation is trivial, I would write:
template <typename T>
class Foo {
...
private:
T w, x, y, z;
public:
friend Foo Bar(const Foo &lhs, const Foo &rhs) {
...
}
};
This doesn't fall foul of the ODR - it's an inline function with external linkage (3.2/5 excludes this from the ODR subject to the definitions being identical, 7.1.2/3 says that it's inline).
However, this doesn't define a function template Bar<T>, it just defines a set of function overloads for Bar. There may be some reason, unstated in the question, that means this won't work for you because you actually need the template.
I like option 1 the best:
template <typename T>
inline Foo<T> Bar(const Foo<T> &lhs, const Foo<T> &rhs) {
return lhs.Bar(rhs);
}
template <typename T>
class Foo {
...
Foo<T> Bar(const Foo<T> &other) const;
private:
T w, x, y, z;
};
Then the functionality is safely contained within the class, but you provide a wrapper function for convenience.
Bar is a template, so it has to be a template in the friend declaration as well.
You don't necessarily have to use a dummy parameter, but could rather use
template <typename U>
friend Foo<U> Bar(const Foo<U> &lhs, const Foo<U> &rhs);
You cannot use T as the template parameter here, as there is already an outer T in scope.
I'm working on an container class template (for int,bool,strings etc), and I've been stuck with this error
cont.h:56: error: expected initializer before '&' token
for this section
template <typename T>
const Container & Container<T>::operator=(const Container<T> & rightCont){
what exactly have I done wrong there?.
Also not sure what this warning message means.
cont.h:13: warning: friend declaration `bool operator==(const Container<T>&, const Container<T>&)' declares a non-template function
cont.h:13: 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
at this position
template <typename T>
class Container{
friend bool operator==(const Container<T> &rhs,const Container<T> &lhs);
public:
In the first case, you're saying just Container the first time instead of Container<T>.
In the second case, I think you need to repeat the template: while member functions of a template class are implicitly templated, friend functions aren't necessarily, so it's necessary to be more explicitly . I'm not sure what exact syntax you need for that purpose, but I think it is:
before the class, template<typename T> bool operator==( etc
in the class, bool operator==<>( etc
I think that's what the error message is trying to convey, though not super-clearly.
In the first case you've done things backwards. When you specify the return type, you have to include the template parameter list into the template identifier (Container<T>), but when you specify parameter type, you don't need to do it (just Container is enough)
template <typename T>
const Container<T> & Container<T>::operator=(const Container & rightCont){
...
You did it the other way around for some reason.
In the second case, when you declare operator == as a friend it simply warns you that that in this case operator == you are referring to is an ordinary function. It can't be a specialization of a template. I.e. for the class Container<int> the function
bool operator==(const Container<int> &rhs, const Container<int> &lhs) {
// ...
}
will be a friend. But specialization of function template
template <class U>
bool operator==(const Container<U> &rhs, const Container<U> &lhs) {
// ...
}
for U == int will not be a friend of Container<int>. If that's your intent, you are OK.
If you wanted to befriend a specific specialization of the above template, you'd have to say
template <typename T>
class Container {
friend bool operator==<T>(const Container<T> &rhs, const Container<T> &lhs);
...
If you wanted to befriend all specialization of the above template, you'd have to say
template <typename T>
class Container {
template <class U>
friend bool operator==(const Container<U> &rhs, const Container<U> &lhs);
...