Lately, when I implement a class I create a nested namespace named operators where I add the stream operators.
I do this because I often need to use them in a namespace other than the class' namespace os I do a
using my_namespace::operators;
just where I want it and that's it.
Here I have an example with a class Point, a class Segment and their stream operators where the Segment's stream calls the Point's stream. But... I cannot compile:
Class Point:
#ifndef POINT_HPP
#define POINT_HPP
#include <iostream>
namespace geom {
class Point
{
public:
Point(int x_, int y_) : x(x_), y(y_) {};
int x;
int y;
};
namespace operators {
std::ostream& operator<<(std::ostream& out, const Point& p)
{
out << "(" << p.x << ", " << p.y << ")";
return out;
}
} // ~ namespace geom::operators
} // ~ namespace geom
#endif // ~ POINT_HPP
Class Segment:
#ifndef SEGMENT_HPP
#define SEGMENT_HPP
#include <iostream>
#include "point.hpp"
namespace geom_2d {
class Segment
{
public:
Segment(const geom::Point& a_, const geom::Point& b_) : a(a_), b(b_) {};
geom::Point a;
geom::Point b;
};
namespace operators {
std::ostream& operator<<(std::ostream& out, const Segment& p)
{
using namespace geom::operators;
out << "[" << p.a << ", " << p.b << "]";
return out;
}
} // ~ namespace geom_2d::operators
} // ~ namespace geom_2d
#endif // ~ SEGMENT_HPP
Main:
#include <iostream>
#include "segment.hpp"
#include "point.hpp"
using namespace geom_2d::operators;
int main()
{
geom::Point p1(3, 5);
geom::Point p2(1, 6);
geom_2d::Segment s(p1, p2);
std::cout << s << std::endl;
return 0;
}
This cannot compile and I get:
../segment.hpp:21: error: no match for ‘operator<<’ in ‘std::operator<< [with _Traits = std::char_traits<char>](((std::basic_ostream<char, std::char_traits<char> >&)((std::ostream*)out)), ((const char*)"[")) << p->geom_2d::Segment::a’
If I remove namespace operators compiles correctly but as I told you, I want to avoid it.
I believe the problem has to do with calling using a namespace operators inside a another namespace operators.
Any ideas?
It is unclear why you want the operators to live in a different namespace than your types. In general the recommendation is that operators should live in the same namespace as the user defined types on which they operate. Doing so enables Argument Dependent Lookup, which in turn will help finding the correct operator when you use it (and will solve your compilation error).
If there is a real reason to have the operators in a different namespace, you can provide a tag type in that namespace and then use inheritance to force ADL to look into the nested namespace (the using-directive won't help with ADL):
namespace A {
namespace operators {
struct tag {};
}
struct B : operators::tag {};
namespace operators {
std::ostream& operator<<(std::ostream& out, const ::A::B& obj) { ... }
}
}
namespace C {
void foo() {
::A::B b;
std::cout << b;
}
}
Note that this is somehow of a hack, and some people will be surprised that the operators are not defined in the A namespace... it works because the set of associated namespaces for a type includes the namespace where the type is defined and also the namespaces of all of it's bases (in this case, ::A::operators is pulled due to the inheritance relationship between ::A::B and ::A::operators::tag)
NOTE: If you define the operators in the same namespace as the type, then you don't need the using-directive at all, as ADL will find them when needed.
The problem is that you've imported the namespace into your code via using, but the library headers don't do this. So they only find the operators in the global namespace, namespace std, or via argument-dependent lookup.
You can probably work around this by doing
using namespace geom_2d::operators;
before
#include <iostream>
but this seems to me like a poor solution.
Related
while trying to implement a metafunction, which needs to exist only if the "abs" function exists for some type, i ran into the folowing problem:
Here are two examples of code i would expect to yield the same results but in fact, they do not:
First example
#include <iostream>
#include <cmath>
using namespace std;
struct Bar{};
template<typename T>
int abs(T& v)
{
return -1;
}
void test()
{
Bar b;
double x = -2;
cout << abs(x) << endl;
cout << abs(b) << endl;
}
int main()
{
test();
}
Yields:
2
-1
Which is what i expect
Second example
#include <iostream>
#include <cmath>
namespace Foo
{
struct Bar{};
using namespace std;
template<typename T>
int abs(T& v)
{
return -1;
}
void test()
{
Bar b;
double x = -2;
cout << abs(x) << endl;
cout << abs(b) << endl;
}
}
int main()
{
Foo::test();
}
Yields:
-1
-1
Why using a namespace here is making the compiler prioritize the "local" abs methodthe over std::abs?
In the second case the using directive places declared names in the nominated namespace in the global namespace for unqualified name lookup. So within the namespace Foo the unqualified name abs declared in this namespace is found. That is the name abs declared in the namespace Foo hides the name abs declared in the global namespace.
From the C++ 14 Standard (7.3.4 Using directive)
2 A using-directive specifies that the names in the nominated
namespace can be used in the scope in which the using-directive
appears after the using-directive. During unqualified name lookup
(3.4.1), the names appear as if they were declared in the nearest
enclosing namespace which contains both the using-directive and the
nominated namespace. [ Note: In this context, “contains” means
“contains directly or indirectly”. — end note ]
The nearest enclosing namespace in the second program is the global namespace.
Below there are two more programs that demonstrate the same principle of the unqualified name lookup when a using directive is used.
#include <iostream>
void s() { std::cout << "The function s() called.\n"; }
struct s
{
s() { std::cout << "The constructor of struct s called.\n"; }
};
void test()
{
s();
}
int main()
{
test();
}
The program output is
The function s() called.
In this demonstration program the declaration of the function s hides the declaration of the structure s.
Second program.
#include <iostream>
namespace N1
{
void s() { std::cout << "The function N1::s() called.\n"; }
}
namespace N2
{
using namespace N1;
struct s
{
s() { std::cout << "The constructor of struct N2::s called.\n"; }
};
void test()
{
s();
}
}
int main()
{
N2::test();
}
The program output is
The constructor of struct N2::s called.
In this case the declaration of the structure with the name s hides the function with the same name s the declaration of which was placed in the global namespace due to the using directive.
For the reason why this takes place you can refer to Vlad's answer. However, if you want to still be able to perform the testing, you can do the testing in separate namespace.
#include <iostream>
#include <cmath>
namespace Foo
{
template<typename T>
int abs(T& v)
{
return -1;
}
}
namespace Test
{
struct Bar{};
using namespace std;
using namespace Foo;
void test()
{
Bar b;
double x = -2;
cout << abs(x) << endl;
cout << abs(b) << endl;
}
}
int main()
{
Test::test();
}
The output is
2
-1
I'm trying to overload the << operator for one of my classes, but the linker keeps failing to find the overload. Been searching online for anything I've missed on how to declare and implement the operator overload but nothing seems to stand out to me. Any ideas how I can fix this?
Undefined symbols for architecture x86_64:
"memath::operator<<(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, memath::Vector3 const&)", referenced from:
_main in mecli.cxx.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
vector3.h
#include <string>
#include <iostream>
namespace memath {
class Vector3 {
public:
double x;
double y;
double z;
Vector3();
std::string to_string() const;
friend std::ostream& operator<<(std::ostream &strm, const Vector3 &a);
};
};
vector3.cxx
#include <string>
#include <iostream>
#include <sstream>
#include "vector3.h"
using namespace memath;
Vector3::Vector3() : Vector3(0, 0, 0) {}
std::string Vector3::to_string() const {
std::ostringstream r;
r << "Vector3" << "(" << this->x << "," << this->y << "," << this->z << ")";
return r.str();
}
std::ostream& operator<<(std::ostream &strm, const Vector3 &a) {
strm << a.to_string();
return strm;
}
mecli.cxx
#include <iostream>
#include <cstdlib>
#include <string>
#include "vector3.h"
int main(int argc, char** argv) {
memath::Vector3 vec1;
std::cout << vec1 << std::endl;
}
because Vector3 is in namespace memath the friend declaration declares memath::operator<<, but you then define ::operator<<. So just make the definition match the declaration:
std::ostream& memath::operator<<(std::ostream &strm, const Vector3 &a) {
// ^~~~~~~~
Follow up question, why doesn't the using namespace memath; seem to matter at the top of the file in this case and exclude this operator overload in particular?
It isn't particular to this operator. Actually is not particular to operators. You get the same behavior with function. And it's not particular to friend declarations.
So let's see this on a simpler example:
namespace ns
{
struct X
{
int foo(int); // => ::ns::X::foo
};
int bar(int); // => ::ns::bar
}
using namespace ns;
int X::foo(int a) { return a + 1; } // (1) => ::ns::X::foo
int bar(int a) { return a * 2; } // (2) => ::bar
Just like in your example, foo works as you expect, but bar is ambiguous, just like your operator<<. So what's the difference between the two? Here's a simplified explanation:
(1): this is the definition of the qualified name foo. X:: is what makes it qualified. So foo is searched within X. But what is X? X is an unqualified name-id. So now an unqualified lookup is performed for X. This means X is searched in the current namespace (global) and in all namespaces brought in by the using directives. In this case X is found only in namespace ns. So X::foo is resolved to ns::X::foo which makes it the declaration of the method foo of the class ns::X.
(2) this is the definition of the unqualified name bar. Since bar is unqualified this is interpreted as the declaration of the name bar in the current namespace (the global namespace). Because bar is a new name being declared a lookup is not performed. So bar is the declaration of ::bar.
Please keep in mind this is a simplified explanation.
Consider the following:
#include <iostream>
namespace X
{
void operator ""_test(unsigned long long x)
{
std::cout << x;
}
}
int main()
{
using namespace X;
10_test;
// 10_X::test; /* doesn't work */
}
I can refer to the user defined literal operator inside the namespace X by an explicit using namespace X;. Is there any way of referring to the literal operator without explicitly including the namespace? I tried the
10_X::test;
but of course doesn't work as the parser believes X refers to the name of the operator.
X::operator ""_test(10)
works but it's clumsy.
#include <iostream>
namespace X {
inline namespace literals {
void operator ""_test(unsigned long long x) {
std::cout << x;
}
}
}
int main() {
{
using namespace X::literals;
10_test;
}
{
using X::operator""_test;
10_test;
}
}
_test is both in X and X::literals. This permits people to using namespace X::literals; without pulling in everything from X, yet within X _test is also available.
Importing an individual literal is a bit annoying.
std does this with both std::chrono and std::literals and std::chrono::literals. inline namespaces let you define subsections of your namespace that you think people would want to import as a block without getting the rest of it.
Just got into C++ and I have a quick question.
After compiling with
g++ *.cpp -o output
I receive this error:
error: 'ostream' in 'class Dollar' does not name a type
These are my three files:
main.cpp
#include <iostream>
#include "Currency.h"
#include "Dollar.h"
using namespace std;
int main(void) {
Currency *cp = new Dollar;
// I want this to print "printed in Dollar in overloaded << operator"
cout << cp;
return 0;
}
Dollar.cpp
#include <iostream>
#include "Dollar.h"
using namespace std;
void Dollar::show() {
cout << "printed in Dollar";
}
ostream & operator << (ostream &out, const Dollar &d) {
out << "printed in Dollar in overloaded << operator";
}
Dollar.h
#include "Currency.h"
#ifndef DOLLAR_H
#define DOLLAR_H
class Dollar: public Currency {
public:
void show();
};
ostream & operator << (ostream &out, const Dollar &d);
#endif
Thank you for your time, and everything helps!
You have a number of errors in the code.
You heavily use using namespace std. This is a bad practice. In particular, this led to the error you faced: you don't have using namespace std in Dollar.h, thus the compiler has no idea what ostream means. Either put using namespace std in Dollar.h too, or better just stop using it and specify the std namespace directly, as in std::ostream.
You use std::ostream in your headers, but you don't include the corresponding standard library header <ostream> in them (<ostream> contains the definition of std::ostream class; for the full I/O library include <iostream>). A really good practice is to include all the dependencies of the header in the header itself, so that it is self-contained and can be safely included anywhere.
You are implementing a stream output operator with signature std::ostream & operator << (std::ostream &, Dollar const &), which is perfectly valid. However, you call it for a pointer to type Dollar. You should rather call it with the object itself, not the pointer, so you should dereference the pointer: std::cout << *cp;.
You implemented the output operator for the Dollar class, but use it for a variable of type Currency: this won't work. There is a way to do this - there do exist virtual methods for this exact reason. However, in this case the operator is a free function, thus it cannot be virtual. So, you should probably add a virtual print method to your Currency class, implement it in Dollar, and call it from output operator:
#include <iostream>
class Currency {
public:
virtual void print (std::ostream &) const = 0;
};
class Dollar : public Currency {
void print (std::ostream & out) const override {
out << "A dollar";
}
};
std::ostream & operator << (std::ostream & out, Currency const & c) {
c.print(out);
return out;
}
int main(/* void is redundant here */) {
Currency *cp = new Dollar;
std::cout << *cp;
// return 0 is redundant in main
}
You need to #include <iostream> within Dollar.h so that your std::ostream & operator is resolved by the compiler.
Update: I made Sergii's changes below, but now I get the error: undefined reference to `cs202::operator<<(std::basic_ostream >&, cs202::Rational const&)'. Any ideas how to fix this? Thanks
I would appreciate help figuring out why I am getting this error:
"error: 'output' is not a member of namespace 'cs202'"
I have a class called Rational as follows:
#ifndef RATIONAL_H
#define RATIONAL_H
namespace cs202{
class Rational
{
private:
int m_numerator;
int m_denominator;
public:
Rational(int nNumerator = 0, int nDenominator = 1) {
m_numerator = nNumerator;
m_denominator = nDenominator;
}
int getNumerator(){return m_numerator;}
int getDenominator(){return m_denominator;}
friend std::ostream& operator<<(std::ostream& output, const Rational& cRational);
};
}
#endif
The implementation file for the friend function which overrides the << operator looks like this:
#include "rational.h"
namespace cs202{
friend std::ostream& operator<<(std::ostream& output, const Rational& cRational)
{
output << cRational.m_numerator << "/" << cRational.m_denominator;
return output;
}
}
Finally, Main looks like this:
#include <iostream>
#include "rational.h"
using namespace std;
using namespace cs202;
int main()
{
Rational fraction1(1, 4);
cs202::output << fraction1 << endl;
return 0;
}
I have tried using cout instead of cs202:output, I have tried with and without the namespace cs202 (which is a requirement of the assignment), and I have tried making the operator overload function a member function of the class rather than a friend function to no avail.
What am I missing? Thanks
I suppose you want it out to standard output (to console)
int main()
{
Rational fraction1(1, 4);
std::cout << fraction1 << endl;
return 0;
}
Also you do not need friend here. "Friend" keyword is used only in a class
#include "rational.h"
namespace cs202{
std::ostream& operator<<(std::ostream& output, const Rational& cRational)
{
output << cRational.m_numerator << "/" << cRational.m_denominator;
return output;
}
}
Thanks, I figured it out. I had to change the placement of the {} for the namespace.