#include <iostream>
namespace outside {
struct A {
int outer = 42;
friend void print(A const& a, std::ostream& os)
{ os << "outside::A " << a.outer << '\n'; }
};
namespace inside {
struct A : outside::A {
int inner = 24;
void print(std::ostream& os) { } // Added for extra difficulty
friend void print(A const& a, std::ostream& os) {
// outside::A::print(a, os); // <- does not compile
os << " inside::A " << a.inner << '\n';
}
};
} // inside
} // outside
int main(int argc, char *argv[]) {
outside::A a_outside;
outside::inside::A a_inside;
print(a_outside, std::cout);
print(a_inside, std::cout);
}
Is there a way to qualify the print function so that both base and derived members are printed? I could move both the friend functions to their closest enclosing namespaces:
#include <iostream>
namespace outside {
struct A { int outer = 42; };
void print(A const& a, std::ostream& os)
{ os << "outside::A " << a.outer << '\n'; }
namespace inside {
struct A : outside::A {
void print(std::ostream& os) { } // Added for extra difficulty
int inner = 24;
};
void print(A const& a, std::ostream& os) {
outside::print(a, os); // <- works
os << " inside::A " << a.inner << '\n';
}
} // inside
} // outside
int main(int argc, char *argv[]) {
outside::A a_outside;
outside::inside::A a_inside;
print(a_outside, std::cout);
print(a_inside, std::cout);
}
This works, here's the result:
outside::A 42
outside::A 42
inside::A 24
Can the same be achieved with the friend functions though? Maybe using using?
EDIT: inside::A::print(std::ostream&) defeats the static cast suggest below, https://stackoverflow.com/a/22585103/710408. Any other options?
I find possible solution:
friend void print(A const& a, std::ostream& os) {
print(static_cast<const outside::A&>(a), os);
os << " inside::A " << a.inner << '\n';
}
Some info why this dont work: https://stackoverflow.com/a/382077/1938348
Conclusion is simple when you define friend function in class body its invisible unless you use ADL.
To made it work as you excepted you need change place of declaration:
namespace outside {
struct A {
int outer = 42;
friend void print(A const& a, std::ostream& os);
};
void print(A const& a, std::ostream& os) {
os << "outside::A " << a.outer << '\n';
}
namespace inside {
struct A : outside::A {
int inner = 24;
friend void print(A const& a, std::ostream& os);
};
void print(A const& a, std::ostream& os) {
outside::print(a, os);
os << " inside::A " << a.inner << '\n';
}
} // inside
} // outside
Do you mean:
friend void print(A const& a, std::ostream& os) {
// outside::A::print(a, os);
print(static_cast<const outside::A&>(a), os);
os << " inside::A " << a.inner << '\n';
}
Related
I'm trying to write a single function template instead of a bunch of similar overloads for the insertion operator. The redundant overloaded versions work, but when I try to unite them in a single function template, the compiler complains of ambiguity. For example:
#include <iostream>
#include <list>
class fooBar
{
public:
fooBar(int iVal): iValue(iVal) {}
int getValue() {return iValue;}
private:
int iValue;
};
class foo
{
public:
foo()
{
for(int i = 0; i < 64; i++)
lstFooBars.push_back(fooBar(i));
}
std::list<fooBar>& getList()
{
return lstFooBars;
}
private:
std::list<fooBar> lstFooBars;
};
class bar
{
public:
bar()
{
for(int i = 0; i < 64; i++)
lstFooBars.push_back(fooBar(i));
}
std::list<fooBar>& getList()
{
return lstFooBars;
}
private:
std::list<fooBar> lstFooBars;
};
std::ostream& operator<<(std::ostream& osOut, fooBar& fbrFooBar)
{
osOut << fbrFooBar.getValue();
return osOut;
}
template <typename T> std::ostream& operator<<(std::ostream& osOut, T& tContainer)
{
for(fooBar fbrFooBar: tContainer.getList())
osOut << "[" << fbrFooBar << "] ";
return osOut;
}
int main()
{
foo fooFoo;
bar barBar;
std::cout << std::endl << fooFoo << std::endl << std::endl;
std::cout << std::endl << barBar << std::endl << std::endl;
return 0;
}
...and the compiler tells me that:
test.cpp: In function ‘std::ostream& operator<<(std::ostream&, T&)’:
test.cpp:63:9: error: ambiguous overload for ‘operator<<’ (operand types are ‘std::ostream’ {aka ‘std::basic_ostream<char>’} and ‘const char [2]’)
63 | osOut << "[" << fbrFooBar << "] ";
| ~~~~~ ^~ ~~~
| | |
| | const char [2]
| std::ostream {aka std::basic_ostream<char>}
Why does it work when you overload the same function over and over for each case and it doesn't compile like this? What am I missing here?
You've inadvertedly added a possible overload for const char* by making this:
template<typename T>
std::ostream& operator<<(std::ostream& osOut, T& tContainer)
If you narrow it down a bit with SFINAE, it should work.
This overload will only work for types with a getList() member function for example:
template<typename T, typename U = decltype(std::declval<T>().getList())>
std::ostream& operator<<(std::ostream& osOut, T& tContainer)
operator<< by default takes chars as argument, not string literals (inside "s) https://www.cplusplus.com/reference/ostream/ostream/operator-free/.
So, in order to make the call in the code you provide not ambiguous, you should try either to use single chars, or std::string:
#include <iostream>
#include <list>
#include <string>
class fooBar
{
public:
fooBar(int iVal): iValue(iVal) {}
int getValue() {return iValue;}
private:
int iValue;
};
class foo
{
public:
foo()
{
for(int i = 0; i < 64; i++)
lstFooBars.push_back(fooBar(i));
}
std::list<fooBar>& getList()
{
return lstFooBars;
}
private:
std::list<fooBar> lstFooBars;
};
class bar
{
public:
bar()
{
for(int i = 0; i < 64; i++)
lstFooBars.push_back(fooBar(i));
}
std::list<fooBar>& getList()
{
return lstFooBars;
}
private:
std::list<fooBar> lstFooBars;
};
std::ostream& operator<<(std::ostream& osOut, fooBar& fbrFooBar)
{
osOut << fbrFooBar.getValue();
return osOut;
}
template <typename T> std::ostream& operator<<(std::ostream& osOut, T& tContainer)
{
for(fooBar fbrFooBar: tContainer.getList())
//osOut << std::string("[") << fbrFooBar << std::string("] "); // solution 1: use std::string
osOut << '[' << fbrFooBar << ']' << ' '; // solution 2: use single chars
return osOut;
}
int main()
{
foo fooFoo;
bar barBar;
std::cout << std::endl << fooFoo << std::endl << std::endl;
std::cout << std::endl << barBar << std::endl << std::endl;
return 0;
}
After reading C++ auto deduction of return type and C++ : Vector of template class, I'm still wondering how to do generic operations (e.g. operator << overload) on object. My code looks like
#include <map>
#include <memory>
#include <string>
#include <iostream>
/**
* Abstract placeholder for Cache polymorphism
*/
class ICache
{
public:
virtual void update() {};
friend std::ostream & operator << (std::ostream & out, const ICache & IC)
{
out << "you should never print this";
}
};
/**
* Concrete. Coupling a name with some cached value
*/
template<typename T>
class Cache :
public ICache
{
const std::string m_name;
T m_cached;
public:
Cache(const std::string & name) :
m_name(name),
m_cached(0)
{}
void update() override
{
// m_cached is synced with remote resource; action depends both from T and m_name
}
void set(const T t)
{
std::cout << m_name << " setting " << +m_cached << " -> " << +t << std::endl;
m_cached = t;
}
inline T get() const noexcept { return m_cached; }
friend std::ostream & operator << (std::ostream & out, const Cache & O)
{
out << "Cache<" << O.m_name << ", " << O.m_cached << ">";
}
};
class CacheMap
{
std::map<std::string, std::unique_ptr<ICache>> m_map;
template<typename T>
Cache<T>* _get_ptr(const std::string & name) const
{
return reinterpret_cast<Cache<T>*>(m_map.at(name).get());
}
public:
template<typename T>
T get(const std::string & name) const
{
return _get_ptr<T>(name)->get();
}
template <typename T>
void set(const std::string & name, T t)
{
_get_ptr<T>(name)->set(t);
}
template <typename T>
void insert(const std::string & name, T def = 0)
{
std::unique_ptr<ICache> up = std::make_unique<Cache<T>>(name);
m_map.insert({name, std::move(up)});
set<T>(name, def);
}
friend std::ostream & operator << (std::ostream & out, const CacheMap & OM)
{
out << "OM{";
for (const auto & IO : OM.m_map)
out << IO.first << ": " << *(IO.second.get()) << ", "; // ver1
// out << IO.first << ": " << (IO.second->get()) << ", "; // ver2
out << "}";
return out;
}
};
int main()
{
CacheMap m;
int i= 70000;
m.insert<int>("i", 69999);
m.insert<short>("s", 699);
m.insert<char>("c", 69);
m.set("i", i);
std::cout << m << std::endl;
}
Line marked with trailing //ver1 shows you should never print this which makes sense; I'm dealing with std::unique_ptr<ICache> objects.
Line marked with trailing //ver2 won't compile at all, and this makes sense too.
What I'd like to do inside CacheMap is to auto-detect, at runtime (hmm sounds bad) the correct T, given a map key, in order to fire the right reinterpret_cast<> and to retrieve m_cached value.
EDIT 1
If compiling with g++ -O3, ver1 line causes a segmentation violation.
Just use a virtual function. The time you cast your variable from Cache<int> pointer type to ICache pointer you lose compile time information about it. That information is lost. You can use dynamic_cast in your friend ICache::operator<< to handle all the different types... To properly resolve type information use virtual functions - ie. unique data tied to each of the class.
#include <map>
#include <memory>
#include <string>
#include <iostream>
class ICache
{
public:
virtual ~ICache() {};
virtual void update() {};
// -------- HERE --------------
virtual std::ostream& printme(std::ostream & out) const = 0;
friend std::ostream& operator << (std::ostream & out, const ICache & IC) {
return IC.printme(out);
}
};
template<typename T>
class Cache : public ICache {
const std::string m_name;
T m_cached;
public:
Cache(const std::string & name): m_name(name), m_cached(0) {}
void update() override {}
void set(const T t) {
std::cout << m_name << " setting " << +m_cached << " -> " << +t << std::endl;
m_cached = t;
}
inline T get() const noexcept { return m_cached; }
std::ostream& printme(std::ostream & out) const override {
out << "Cache<" << m_name << ", " << m_cached << ">";
return out;
}
};
class CacheMap {
std::map<std::string, std::unique_ptr<ICache>> m_map;
template<typename T>
Cache<T>* _get_ptr(const std::string & name) const {
return dynamic_cast<Cache<T>*>(m_map.at(name).get());
}
public:
template<typename T>
T get(const std::string & name) const {
return _get_ptr<T>(name)->get();
}
template <typename T>
void set(const std::string & name, T t) {
_get_ptr<T>(name)->set(t);
}
template <typename T>
void insert(const std::string & name, T def = 0) {
std::unique_ptr<ICache> up = std::make_unique<Cache<T>>(name);
m_map.insert({name, std::move(up)});
set<T>(name, def);
}
friend std::ostream& operator << (std::ostream & out, const CacheMap & OM) {
out << "OM{";
for (const auto & IO : OM.m_map)
out << IO.first << ": " << *(IO.second.get()) << ", "; // ver1
// out << IO.first << ": " << (IO.second->get()) << ", "; // ver2
out << "}";
return out;
}
};
int main()
{
CacheMap m;
int i= 70000;
m.insert<int>("i", 69999);
m.insert<short>("s", 699);
m.insert<char>("c", 69);
m.set("i", i);
std::cout << m << std::endl;
}
will output on godbolt:
i setting 0 -> 69999
s setting 0 -> 699
c setting 0 -> 69
i setting 69999 -> 70000
OM{c: Cache<c, E>, i: Cache<i, 70000>, s: Cache<s, 699>, }
I just spotted, to protect against very bad and hard to debug errors, I remind you to use dynamic_cast instead of reintepret_cast in CacheMap::_get_ptr().
There are various ways, but generally I would implement a single operator<<() that calls a virtual function.
class ICache {
protected: // so the function is only accessible to derived classes
virtual std::ostream print(std::ostream &out) const = 0; // force derived classes to override
friend std::ostream &operator<<(std::ostream &out, const ICache& c);
};
Then place a single definition of the operator<< in a single compilation unit
// definition of class ICache needs to be visible here
std::ostream &operator<<(std::ostream &out, const ICache& c)
{
return c.print(out);
}
And to implement the derived class
// definition of ICache here
template<class T>
class Cache: ICache
{
protected:
std::ostream print(std::ostream &out) const override
{
// output a Cache<T>
return out;
}
};
The advantage of this is that each class takes responsibility for outputting itself, rather than a container class having to work out which output function to call (and the opportunity for a programmer to forget to do that).
First, reinterpret_cast is a dangerous thing. In contexts of polymorphism you mostly want to use dynamic_cast.
You problem is not about templates etc at all, but it is more about that you want to make the operator<< virtual, which is not possible, since it is a friend function. An easy workaround is the following:
class ICache {
virtual void print(std::ostream &out) const { // Prefer pure virtual
out << "Never print this\n";
}
friend std::ostream &operator<<(std::ostream &out, const ICache& c) {
c.print(out);
return out;
}
};
template<class T>
class Cache: ICache {
void print(std::ostream &out) const override {
out << "Print this instead\n";
}
};
will do what you want without any casting.
I'm trying to do
cout << Print(cout); However, there is an "invalid operands to binary expression ('ostream' (aka 'basic_ostream') and 'ostream')" error when compiling.
#include <iostream>
using namespace std;
ostream& Print(ostream& out) {
out << "Hello World!";
return out;
}
int main() {
cout << Print(cout);
return 0;
}
Why this doesn't work?
How can I fix this? Thanks!!
The syntax you might be looking for is std::cout << Print << " and hello again!\n";. The function pointer is treated as a manipulator. A built-in operator << takes the pointer to Print and calls it with cout.
#include <iostream>
using namespace std;
ostream& Print(ostream& out) {
out << "Hello World!";
return out;
}
int main() {
cout << Print << " and hello again!\n";
return 0;
}
Here is your second request:
#include <iostream>
#include <vector>
#include <iterator>
template <class Argument>
class manipulator
{
private:
typedef std::ostream& (*Function)(std::ostream&, Argument);
public:
manipulator(Function f, Argument _arg)
: callback(f), arg(_arg)
{ }
void do_op(std::ostream& str) const
{
callback(str, arg);
}
private:
Function callback;
Argument arg;
};
template <class T>
class do_print : public manipulator<const std::vector<T>&>
{
public:
do_print(const std::vector<T>& v)
: manipulator<const std::vector<T>&>(call, v) { }
private:
static std::ostream& call(std::ostream& os, const std::vector<T>& v)
{
os << "{ ";
std::copy(v.begin(), v.end(),
std::ostream_iterator<T>(std::cout, ", "));
return os << "}";
}
};
template <class Argument>
std::ostream& operator<<(std::ostream& os, const manipulator<Argument>& m)
{
if (!os.good())
return os;
m.do_op(os);
return os;
}
template<class T>
do_print<T> Print(const std::vector<T>& v)
{
return do_print<T>(v);
}
int main()
{
std::vector<int> v{1, 2, 3};
std::cout << Print(v);
}
Here is what I would like to do:
class Msg {
int target;
public:
Msg(int target): target(target) { }
virtual ~Msg () { }
virtual MsgType GetType()=0;
};
inline std::ostream& operator <<(std::ostream& ss,Msg const& in) {
return ss << "Target " << in.target;
}
class Greeting : public Msg {
std::string text;
public:
Greeting(int target,std::string const& text) : Msg(target),text(text);
MsgType GetType() { return TypeGreeting; }
};
inline std::ostream& operator <<(std::ostream& ss,Greeting const& in) {
return ss << (Msg)in << " Text " << in.text;
}
Unfortunately, this doesn't work as the cast to Msg on the second last line fails as Msg is abstract. I would however like to have the code to output the information for the parent in only one place. What is the correct way to do this? Thanks!
EDIT: Sorry, just to be clear, it is this line return ss << (Msg)in << " Text " << in.text; I don't know how to write.
Try ss<<(Msg const&)in.
And probably you have to make operator a friend of Greeting class.
#include "iostream"
#include "string"
typedef enum { TypeGreeting} MsgType;
class Msg {
friend inline std::ostream& operator <<(std::ostream& ss,Msg const& in);
int target;
public:
Msg(int target): target(target) { }
virtual ~Msg () { };
virtual MsgType GetType()=0;
};
inline std::ostream& operator <<(std::ostream& ss,Msg const& in) {
return ss << "Target " << in.target;
}
class Greeting : public Msg {
friend inline std::ostream& operator <<(std::ostream& ss,Greeting const& in);
std::string text;
public:
Greeting(int target,std::string const& text) : Msg(target),text(text) {};
MsgType GetType() { return TypeGreeting; }
};
inline std::ostream& operator <<(std::ostream& ss,Greeting const& in) {
return ss << (Msg const&)in << " Text " << in.text;
}
int _tmain(int argc, _TCHAR* argv[])
{
Greeting grt(1,"HELLZ");
std::cout << grt << std::endl;
return 0;
}
Not great design, but solves your problem.
How do I overload the << operator for enums that are members of a class. Specifically, I have the following code below:
#include <iostream>
using namespace std;
namespace foo {
class bar {
public:
enum a { b, c, d};
static void print() {
cout << b << endl;
}
};
ostream& operator<< (ostream& os, bar::a var) {
switch (var) {
case bar::b:
return os << "b";
case bar::c:
return os << "c";
case bar::d:
return os << "d";
}
return os;
}
}
int main() {
foo::bar::print();
return 0;
}
How can I get the print function to print "b" instead of "1"?
Here is a simple solution :
#include <iostream>
using namespace std;
namespace foo {
class bar {
public:
enum a { b, c, d};
static void print();
};
ostream& operator<< (ostream& os, bar::a var) {
switch (var) {
case bar::b:
return os << "b";
case bar::c:
return os << "c";
case bar::d:
return os << "d";
}
return os;
}
void bar::print() {
cout << b << endl;
}
}
int main() {
foo::bar::print();
return 0;
}
[EDIT] As previously stated by aschepler, you only need to ensure that operator<<(ostream &, bar::a) is visible before the definition of bar::print.
class bar {
public:
enum a { b = 'b', c = 'c', d = 'd' };
static void print() {
cout << char(b) << endl;
}
};
The problem is that your use of cout << bar:: comes before your ostream<< bar:: overload is declared, so it's not calling your overload. Move the definition down.
class bar {
public:
enum a { b, c, d };
static void print();
};
ostream& operator<< (ostream& os, bar::a var) {
...
void bar::print()
{
cout << b << endl;
}
EDIT: I see some else posted that while I was typing this.