Friend operator in different namespace - c++

Currently the following code is not working:
namespace inner
{
struct Test
{
Test() : n(0) { }
friend int ::operator+(const Test& a, const Test& b);
private:
int n;
};
}
int operator+(const inner::Test& a, const inner::Test& b)
{
return a.n + b.n;
}
and the error I get is
error: 'int operator+(const inner::Test&, const inner::Test&)' should have been declared inside '::'
friend int ::operator+(const Test& a, const Test& b);
^
I thought qualifing the namespace would fix the problem but it doesn't. What's a workaround?

A friend declaration can only introduce a name into the immediately surrounding namespace.
If you want to befriend a function in any other namespace, then you'll need to declare that function, in its namespace, before the friend declaration. As the error message says.
In this case, you probably want the operator to be in inner rather than the global namespace. Argument-dependent lookup will still find it in an expression like test_a + test_b, even if it's not otherwise in scope.

You have to declare the operator before its usage in the structure.

Related

Member is inaccessible when overloaded operator is friended

The code doesn't link when I try to compile, the error is "undefined reference to operator*" and I think this may be the problem.
This is my .h file:
namespace space{
class Number{
.
.
public:
friend Number operator*(double scaler, const Number& one);
private:
int val;
std::string unit;
.
}
This is the .cpp file:
using namespace space;
Number operator*(double scaler, const Number& one){
Number temp((one.val * scaler), one.unit);
return temp;
}
But I'm getting the error (it's right on the one.val):
member "space::Number::val" (declared at line 47 of ".../Number.hpp") is inaccessibleC/C++(265)
The friend declaration is a declaration of a function:
namespace space{
class Number{
friend Number operator*(double scaler, const Number& one);
// ...
};
As this is inside a namespace, the function that is declared is space::operator*. Then you define ::operator* in the global namespace. Those are two different functions. You made one operator a friend of the class, but define a different one.
The operator that you made a friend must be defined inside the namespace (or you declare the one in global scope as friend):
namespace space {
Number operator*(double scaler, const Number& one){
Number temp((one.val * scaler), one.unit);
return temp;
}
}

C++ namespaces, inner classes and operator resolution

In the C++ namespace myspace I have a class Outer which in turn has an inner class Inner. While I can declare and define a global friend operator QDataStream& operator<<(QDataStream& s, const myspace::Outer& o), I cannot see how to declare a global friend operator QDataStream& operator<<(QDataStream& s, const myspace::Outer::Inner& o). The commented out lines represent a failed attempt. I do not see how to declare the inner class without defining the outer.
namespace myspace {
class Outer;
//class Outer::Inner;
}
QDataStream& operator<<(QDataStream& s, const myspace::Outer& o);
//QDataStream& operator<<(QDataStream& s, const myspace::Outer::Inner& o);
namespace myspace {
class Outer {
friend QDataStream& (::operator <<)(QDataStream&, const Outer&);
class Inner {
//friend QDataStream& (::operator <<)(QDataStream&, const Inner&);
int i;
};
int o;
};
}
I have read
Namespaces and operator resolution, C++ Defining the << operator of an inner class, Accessing private class in operator<< in namespace
and Operator overloading, name resolution and namespaces, but none seem to work.
If I uncomment these lines, the first gives the error message "outer.h:7: error: 'Inner' in 'class myspace::Outer' does not name a type
class Outer::Inner;
^"
This seems to be the key. I cannot declare the inner class.
I am using C++ 11.
This question is not a duplicate of Forward declaration of nested types/classes in C++ if it can can be solved without forward reference.
Given the time lapse, I am posting the correct answer given by Andreas H.
namespace myspace {
class Outer {
class Inner {
friend QDataStream& operator<<(QDataStream&, const Inner&);
int i;
};
friend QDataStream& operator<<(QDataStream&, const Outer&);
friend QDataStream& operator<<(QDataStream&, const Inner&);
int o;
};
QDataStream& operator<<(QDataStream& s, const myspace::Outer& o) {
s << o.o;
return s;
}
QDataStream& operator<<(QDataStream& s, const myspace::Outer::Inner& i) {
s << i.i;
return s;
}
}

Friend functions and namespaces

I'm trying to overload the << operator for a class that's part of a user-defined namespace. What's interesting is that if I remove all that namespace stuff, the program compiles and runs without a problem, but the fact that the class resides in a namespace somehow makes the compilation process for the file A.cpp fail with an error saying that I'm trying to access private data in class A (demo.cpp compiles fine). Please, take a look at my three-file program and the compilation error that I get:
demo.cpp:
#include <iostream>
#include "A.h"
int main() {
usr::A a(4);
std::cout << a << std::endl;
return 0;
}
A.h:
#ifndef A_H_
#define A_H_
#include <iostream>
namespace usr {
class A {
private:
int m_x;
public:
A(int x);
friend std::ostream& operator<<(std::ostream& os, const usr::A& a);
};
}
#endif // A_H_
A.cpp:
#include "A.h"
usr::A::A(int x) : m_x(x) {}
std::ostream& operator<<(std::ostream& os, const usr::A& a) {
os << a.m_x;
return os;
}
Error:
$ g++ -c A.cpp
In file included from A.cpp:1:0:
A.h: In function ‘std::ostream& operator<<(std::ostream&, const usr::A&)’:
A.h:10:17: error: ‘int usr::A::m_x’ is private
int m_x;
^
A.cpp:7:13: error: within this context
os << a.m_x;
^
Non-qualified friend declarations always refer to members of the smallest enclosing namespace. When a class is declared in namespace usr, any non-qualified friend declaration inside that class refers to members of usr. I.e. your friend declaration declared usr::operator << as a friend.
The global ::operator << remains a non-friend in this case, which is why you get the error when you attempt to access private members of usr::A from ::operator <<.
If you want this to work, you have to either
Make your operator << a member of usr, or
Make sure the friend declaration explicitly refers to global operator << by using a qualified name ::operator << (this will also require introducing ::operator << before trying to refer to it by its qualified name).
I would suggest the first approach. If your class A is a member of namespace usr, then it is a good idea to declare all functions that handle A as members of usr as well. This will help you to avoid many problems with argument-dependent lookup (ADL) down the road.
But if for some reason you need your operator << to remain a member of global namespace, then here are the hoops you'd have to jump through to make it compile (combined into a single translation unit)
// Pre-declare `usr::A` to enable pre-declaration of our `::operator <<`
namespace usr {
class A;
}
// Pre-declare our `::operator <<`
std::ostream& operator<<(std::ostream& os, const usr::A& a);
namespace usr {
class A {
private:
int m_x;
public:
A(int x);
friend std::ostream& ::operator<<(std::ostream& os, const usr::A& a);
// Friend declaration uses qualified name - it explicitly
// refers to `::operator <<` declared above
};
}
usr::A::A(int x) : m_x(x) {}
std::ostream& operator<<(std::ostream& os, const usr::A& a) {
os << a.m_x;
return os;
}
int main() {
usr::A a(4);
std::cout << a << std::endl;
}
Under GCC you have to separate return-type and scope resolution operator (:: token) via some access modifier (reference on const or pointer).
For example, this will not compile under g++7.2.0:
std::string f(int a);
namespace NS
{
class C
{
friend std::string ::f(int a);
// scope operator ^^ is absolutely needed
}
}
But this will:
std::string f(int a);
namespace NS
{
class C
{
friend std::string const ::f(int a);
// see const keyword ^
}
}
And this will:
std::string f(int a);
namespace NS
{
class C
{
friend std::string& ::f(int a);
// see ref symbol ^
}
}

Visual C++ | qualifier must be a base class of "Foo"

Why does the following code
class Foo {
public:
bool std::operator==(const Foo&, const Foo&);
};
comes up as an error ' qualifier must be a base class of "Foo" '
I get a different (maybe more reasonable) error message here:
main.cpp:4:48: error: invalid use of '::'
bool std::operator==(const Foo&, const Foo&);
^
You cannot arbitrarily overload binary operator function as class member operator functions (see Operator Overloading).
You cannot do this referencing the std namespace
What you probably wanted is
class Foo {
public:
bool operator==(const Foo&) const;
};
If you're really sure you want to overload this in the std:: namespace, you can write:
namespace std {
bool operator==(const Foo& op1, const Foo& op2) {
return op1.operator==(op2);
}
}
or simply overload the binary operator==() function in the global namespace:
bool operator==(const Foo& op1, const Foo& op2) {
return op1.operator==(op2);
}
In-class binary operators have an implicit Foo const & as the left-hand side. Thus, you should only include one Foo const & as a parameter, not two.
edit: also, as mentioned in the other answer, you would have to drop the std:: in this case too.

operator overloading c++

I am trying to preform operator overloading in C++;
for some reason the compiles keeps on giving me the error
error: ‘bool Matrix::operator==(const Matrix&, const Matrix&)’ must take exactly one argument
Now, I know that there is some way to to it with one argument using this, but I understood that by using friend I can do it this way, but it still is not working.
Here is my code,
Thanks in advance.
class Matrix{
public:
Matrix();
friend bool operator==(Matrix &mtrx1,Matrix &mtrx2);
friend bool operator!=(Matrix &mtrx1,Matrix &mtrx2);
protected:
std::vector<Cell> _matrix;
int _row;
int _col;
};
inline bool Matrix::operator==(const Matrix& mtrx1, const Matrix& mtrx2){
/* .......... */
}
The operator== member function is declared as:
class foo {
public:
bool operator==( foo const & rhs ) const;
};
The operator== global function is declared as:
bool operator==( foo const & lhs, foo const & rhs );
Generally, the member function is declared and defined first. Then, the global function is defined in terms of the member function as
Only one between the member function and global function is declared and defined. Having both of them is ambiguous for statements like (1) in the following
foo f1;
foo f2;
bool f1EqualsF2 = (f1 == f2 ); // (1), ambiguous
and in such cases compiler returns error. In g++, the error message looks like
equals.cpp:24: error: ambiguous overload for ‘operator==’ in ‘f1 == f2’
equals.cpp:8: note: candidates are: bool foo::operator==(const foo&) const
equals.cpp:17: note: bool operator==(const foo&, const foo&)
Whenever operator== is done, its recommended to do the corresponding operator!=.
Although you've put the friend declaration inside the class, it's not a member. So the function definition should be a non-member:
inline bool operator==(const Matrix& mtrx1, const Matrix& mtrx2) {...}
You also need to add const qualifiers to the arguments of the declarations, to match those in the definition.
class Matrix{
public:
Matrix();
friend bool operator==(const Matrix &mtrx1, const Matrix &mtrx2);
friend bool operator!=(const Matrix &mtrx1, const Matrix &mtrx2);
protected:
std::vector<Cell> _matrix;
int _row;
int _col;
};
inline bool operator==(const Matrix& mtrx1, const Matrix& mtrx2){
/* .......... */
return true;
}
Pass compilation in Visual Studio 2005.
omit the const qualifier in your friend declaration
don't need Matrix:: in operation== definition
You do it with 2 parameters if you are doing it outside of the class, not as a member function.
As a member function you need only 1 parameter (the other parameter is *this)