Look up overloaded operators in outer namespace in class design - c++

How to let a wrapper class in a namespace know that in the outer/global namespace there may exist overloaded operators for the object that it wraps?
Note: I've heard of ADL, or Koenig lookup, but I met a real problem.
The Real Design Problem
I want to design a header-only library. Say I put everything in namespace my. The part related to this question can be simplified to something like a template wrapper item.
// my.hpp
#include <iostream>
namespace my
{
template<typename T>
struct item
{
T thing;
item(T t) : thing(t) {}
};
template<typename T>
std::ostream & operator<<(std::ostream & os, const item<T> & it)
{
os << it.thing;
return os;
}
}
With item what I want to achieve is that:
item<T> wraps a T object (with T object to be provided by user)
If operator<<(std::ostream &, const T &) is not defined in <iostream>, then I assume the user has overloaded operator<<(std::ostream &, const T &), and I want operator<<(std::ostream &, const item<T> &) to call it.
A Concrete User Example
Consider a set of user code that does so for T = std::vector<double>
// user.hpp
// #include guard omitted
#include <iostream>
#include <vector>
std::ostream & operator<<(std::ostream &, const std::vector<double> &);
and
// user.cpp
#include <iostream>
#include <vector>
std::ostream & operator<<(std::ostream & os, const std::vector<double> & v)
{
for (const auto & e : v)
os << e << " | ";
return os;
}
int main()
{
std::vector<double> vec = {3.14, 2.83};
std::cout << my::item<std::vector<double>>(vec);
}
Now if the user put
#include "user.hpp"
#include "my.hpp"
at the beginning of user.cpp, everything would be fine and g++ user.cpp would compile as expected.
However, if the user changed the order and put
#include "my.hpp"
#include "user.hpp"
the compiler would generate an error saying
my.hpp: In function 'std::ostream& my::operator<<(std::ostream&, const my::item<T>&)':
my.hpp:15:23: error: '::operator<<' has not been declared
Certainly I do not want the result to be dependent on the order of #include.
My question is: As a designer of namespace my and wrapper item<T>, what can I do to my and item<T> so that item<T> can correctly spot and call operator<<(std::ostream, const T &) if it is provided by user?
Thank you for your time!
Update: For your information, g++ --version returns
g++ (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 7.3.0

After reading a question and answer on meta, and following suggestions from comments, I am moving some "updates" in my own question and posting them formally as a self-answer. I am doing so in the hope that this will help someone in future who happen to meet the same kind of problem. Thank you!
As #xskxzr correctly points out in the comment, there is something bad in the user code. To be specific,
it is bad to declare functions/operations whose parameters are all std entities as you cannot add such declarations into std to make use of ADL
In this case, the problem lies on the side of the user, not on the designer.
Now if the user made a change
// user.hpp
#include <iostream>
#include <vector>
// CHANGE: (privately) inherit from std::vector<double>, rather than overload directly
struct DoubleVector : private std::vector<double>
{
using std::vector<double>::vector;
friend
std::ostream & operator<<(std::ostream &, const DoubleVector &);
};
std::ostream & operator<<(std::ostream &, const DoubleVector &);
and
// user.cpp
#include "my.hpp"
#include "user.hpp"
#include <iostream>
#include <vector>
// CHANGE: use a user-defined DoubleVector class
std::ostream & operator<<(std::ostream & os, const DoubleVector & c)
{
for (const auto & e : c)
os << e << " | ";
return os;
}
int main()
{
DoubleVector vec = {3.14, 2.83};
std::cout << my::item<DoubleVector>(vec);
}
Then the user code would compile regardless of the order of #include "my.hpp" and #include "user.hpp".

Related

expected primary-expression before ‘.’ token

I am fairly new to classes. I created a class called Counter which basically creates a counter object and has certain data members and function members associated with it.
The header file for the class is:
#ifndef c
#define c
#include <iostream>
#include <string>
#include <vector>
using std::vector; using std::string; using std::ostream;
class Counter{
int v_;
public:
vector<string> log_;
int initialized_;
Counter(int);
int value();
int get_v() const { return v_; } //getter
void set_v(int val) { v_ = val; } //setter
friend ostream & operator<<(ostream &, Counter &);
friend Counter operator+(const Counter &, const Counter &);
};
ostream & operator<<(ostream &, Counter &);
Counter operator+(const Counter &, const Counter &);
#endif
and the cpp implementation file looks like this:
#include "counter.h"
#include <iostream>
#include <vector>
#include <string>
using std::string; using std::vector; using std::ostream;
Counter::Counter(int a){
v_ = a;
initialized_ = a;
log_.push_back("Constructor called with a " + std::to_string(a));
}
int Counter::value(){
log_.push_back("value called. returned a " + std::to_string(v_));
return (v_--);
}
ostream & operator<<(ostream & out, Counter & c){
c.log_.push_back("<< called."); //line 1
out << "Counter("<< c.initialized_ << ")#" << c.v_; //line 2
return out;
}
Counter operator+(const Counter & c_one, const Counter & c_two){
Counter c_three(c_one.initialized_ + c_two.initialized_);
c_three.set_v(c_one.get_v()+c_two.get_v());
return c_three;
}
When I compile the file I get bombarded with expected primary-expression before ‘.’ token in line 1 and line 2 of the "<<" operator overloaded function. I really have no idea as to why this is happening. Any help?
What is c? You've defined it as nothing and then you use
c.log_.push_back(...)
Which the preprocessor changes to
.log_.push_back(...)
I'm not sure what you're trying to do but the error clearly states it's looking for an expression before the period, where it appears you have none.

ostream in class does not have a type

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.

Overloading Iostream C++

I'm writing a header only matrix3x3 implementation which I want to be independent and not relying on other headers except for a vector3 header which i also wrote.
Currently, I want it to overload ostream << operator but I don't want to include the iostream in it.
Is it possible to make the overloading optional and work if ostream is included, and if its not included to have all the rest work fine just without the overload?
I thought about the possibility of checking if the ostream header is included but it has a major flaw because it would not work correctly if iostream was included after the matrix3x3 header.
Edit:
I've replaced iostream with ostream as i think it created a bit of confusion regarding the point of the question.
Why not use <iosfwd>?
Example:
#include <iosfwd>
class Example
{
public:
Example(int i) : i(i) {}
private:
int i;
friend std::ostream& operator<<(std::ostream& os, Example const& example);
};
#include <iostream>
int main()
{
Example e(123);
std::cout << e << '\n';
}
std::ostream& operator<<(std::ostream& os, Example const& example)
{
os << example.i;
return os;
}
Note that you cannot safely forward-declare standard classes in your own code. Related questions:
Forward declare an STL container?
Forward Declaration of variables/classes in std namespace

Why can't the compiler find this operator<< overload?

I'm trying to write overloads of operator<< for specific instantiations of standard library containers that will be stored in a boost::variant. Here's a small example that illustrates the problem:
#include <iostream>
#include <vector>
std::ostream & operator<<( std::ostream & os, const std::vector< int > & ) {
os << "Streaming out std::vector< int >";
return os;
}
std::ostream & operator<<( std::ostream & os, const std::vector< double > & ) {
os << "Streaming out std::vector< double >";
return os;
}
#include <boost/variant.hpp>
typedef boost::variant< std::vector< int >, std::vector< double > > MyVariant;
int main( int argc, char * argv[] ) {
std::cout << MyVariant();
return 0;
}
Clang's first error is
boost/variant/detail/variant_io.hpp:64:14: error: invalid operands to binary expression ('std::basic_ostream<char>' and 'const std::vector<int, std::allocator<int>>')
out_ << operand;
~~~~ ^ ~~~~~~~
I realize that the #include <boost/variant.hpp> is in an odd place. I'm pretty sure the problem had to do with two-phase name lookup in templates, so I moved the #include in an attempt to implement fix #1 from the clang documentation on lookup. Fix #2 from that documentation isn't a good option because I believe adding my overloaded operator<< to the std namespace would lead to undefined behavior.
Shouldn't defining my operator<<s before the #include allow the compiler to find the definitions? That technique seems to work in the following example, adapted from the same clang page.
#include <iostream>
namespace ns {
struct Data {};
}
std::ostream& operator<<(std::ostream& out, const ns::Data & data) {
return out << "Some data";
}
namespace ns2 {
template<typename T>
void Dump( std::ostream & out, const T & value) {
out << value;
}
}
int main( int argc, char * argv[] ) {
ns2::Dump( std::cout, ns::Data() );
}
During template instantiation function template depending on a template type are only found during phase II look-up. Phase II look-up doesn't consider names visible at the point of use but only considers names found based on argument dependent look-up. Since the only associated namespace for std::ostream and std::vector<int> is namespace std it doesn't look for your output operators defined in the global namespace. Of course, you are not allowed to add these operators to namespace std which is a real catch: you can only define these operators for containers involving, at least, one user define type! On possibly way around this restriction is to add a custom allocator which is simply derived from std::allocator<T> but lives in a suitable user-define namespace: you can then define the output operators in this namespace. The drawback of this approach is that std::vector<T> (i.e., without an allocator parameter) is pretty much a vocabulary type.
Moving the declarations around doesn't help: phase II name look-up doesn't really depend on the order of the declaration except that the declarations have to precede the point of instantiation. The only proper fix is to define the operators in a namespace being sought by phase II look-up which pretty much means that the types being printed have to involve a user-defined type.

Operator << overload in c++

#include <iostream>
#include <fstream>
class obj
{
public:
int i;
friend ostream& operator<<(ostream& stream, obj o);
}
void main()
{
obj o;
ofstream fout("data.txt");
fout<<o;
fout.close();
}
This is the my code, am getting error.
error : ostream : ambiguous symbol.
any one can help me.
You need to specify the namespace. Prefix ostream with std - i.e. std::ostream
Also, you should pass the obj type by const reference to the operator:
friend ostream& operator<<(ostream& stream, const obj& o);
You didn't use namespace std (using namespace std is habit anyway) so the compiler doesn't know what on earth an ostream is.In addition to that, you didn't actually define operator<<, only declared it, so even if it recognizes it, it won't know what to do since you didn't tell it.
As I see it you need to
Add
using std::ostream;
using std::ofstream;
Add a ; after the class declaration
Povide an implementation for the << operator.
In the end you should end up with something like:
#include <iostream>
#include <fstream>
using std::ostream;
using std::ofstream;
class obj
{
public:
int i;
friend ostream& operator<<(ostream& stream, const obj& o);
};
ostream& operator<<(ostream& stream, const obj& o)
{
std::cout << o.i;
return stream;
}
int main()
{
obj o;
ofstream fout("data.txt");
fout << o;
fout.close();
}
ofstream is in namespace std, so you need to declare fout like this:
std::ofstream fout("data.txt");
I'll assume you simply omitted the definition of your operator<< function for simplicity. Obviously, you'll need to write the body of that function for your next line to compile.
ostream is a member of the std:: namespace, so either put a using namespace std; before your class declaration or explicitly refer to it with std::ostream.
Consider passing your object in as a reference otherwise a new obj object will be created each time via the copy constructor.
friend ostream& operator<<(ostream& stream, obj& o);