So I want to write an indent output class that can be used like this:
Debug f;
f.open("test.txt");
f << Debug::IndS << "Start" << std::endl;
f << Debug::Ind << "test" << std::endl;
f << Debug::IndE << "End" << std::endl;
which would output:
Start
test
End
So IndS would print out current indent and increment indent, Ind would print out the current indent and IndE would decrement indent and print out the current indent. I have tried to create it like so:
class Debug : public std::ofstream {
public:
Debug();
~Debug();
private:
std::string IndentText;
int _Indent;
public:
void SetIndentText(const char* Text);
inline void Indent(int Amount);
inline void SetIndent(int Amount);
inline std::ofstream& Ind (std::ofstream& ofs);
inline std::ofstream& IndS(std::ofstream& ofs);
inline std::ofstream& IndE(std::ofstream& ofs);
};
Debug::Debug () : std::ofstream() {
IndentText = " ";
}
Debug::~Debug () {
}
void Debug::SetIndentText (const char* Text) {
IndentText = Text;
}
void Debug::Indent (int Amount) {
_Indent += Amount;
}
void Debug::SetIndent(int Amount) {
_Indent = Amount;
}
std::ofstream& Debug::Ind (std::ofstream& ofs) {
for (int i = 0;i < _Indent;i++) {
ofs << IndentText;
}
return ofs;
}
std::ofstream& Debug::IndS (std::ofstream& ofs) {
ofs << Ind;
_Indent++;
return ofs;
}
std::ofstream& Debug::IndE (std::ofstream& ofs) {
_Indent--;
ofs << Ind;
return ofs;
}
So I think there are a few problems with this:
It does not compile. Errors with no match for 'operator<<' (operand types are 'std::ofstream {aka std::basic_ofstream<char>}' and '<unresolved overloaded function type>') ofs << Ind; candidates are: blah blah
I don't override all constructors. Is there a way to do this? I think I just have to rewrite all the constructors to do IndentText = " "; and delegate the overloaded constructor
Could someone help me with this? Thanks!
You usually shouldn't inherit std::ostream or implementations of it like std::ofstream. Wrap them into another class instead.
Here's a short sketch of my ideas mentioned in the comments
#include <iostream>
#include <fstream>
using namespace std;
class Logger {
public:
Logger(ostream& os) : os_(os), curIndentLevel_(0) {}
void increaseLevel() { ++curIndentLevel_; }
void decreaseLevel() { --curIndentLevel_; }
private:
template<typename T> friend ostream& operator<<(Logger&, T);
ostream& os_;
int curIndentLevel_;
};
template<typename T>
ostream& operator<<(Logger& log, T op) {
for(int i = 0; i < log.curIndentLevel_ * 4; ++i) {
log.os_ << ' ';
}
log.os_ << op;
return log.os_;
}
int main() {
Logger log(cout);
log.increaseLevel();
log << "Hello World!" << endl;
log.decreaseLevel();
log << "Hello World!" << endl;
return 0;
}
Output
Hello World!
Hello World!
Live Sample
Here's a little variant, showing how you can shortcut the coding with operator<<() overloads:
class Logger {
public:
Logger(ostream& os) : os_(os), curIndentLevel_(0) {}
Logger& increaseLevel() { ++curIndentLevel_; return *this; }
Logger& decreaseLevel() { --curIndentLevel_; return *this; }
// ... as before ...
};
int main() {
Logger log(cout);
log.increaseLevel() << "Hello World!" << endl;
log.decreaseLevel() << "Hello World!" << endl;
return 0;
}
Live Sample
The same way you can go to provide additional I/O manipulator style free functions.
Alternative solution:
#include <iostream>
#include <fstream>
class IndentClass {
public:
IndentClass();
~IndentClass();
private:
std::string IndentText;
int _Indent;
public:
inline void SetIndentText(const char* Text);
inline void Indent(int Amount);
inline void SetIndent(int Amount);
inline void ind (std::ostream& ofs);
class Ind_t {
public:
IndentClass& state;
Ind_t (IndentClass& _state) : state(_state) {}
friend inline std::ostream& operator<< (std::ostream& ofs, Ind_t& ind);
};
class IndS_t {
public:
IndentClass& state;
IndS_t (IndentClass& _state) : state(_state) {}
friend inline std::ostream& operator<< (std::ostream& ofs, IndS_t& ind);
};
class IndE_t {
public:
IndentClass& state;
IndE_t (IndentClass& _state) : state(_state) {}
friend inline std::ostream& operator<< (std::ostream& ofs, IndE_t& ind);
};
Ind_t Ind;
IndS_t IndS;
IndE_t IndE;
};
IndentClass::IndentClass () : IndentText(" "), _Indent(0), Ind(*this), IndS(*this), IndE(*this) {
}
IndentClass::~IndentClass () {
}
void IndentClass::SetIndentText (const char* Text) {
IndentText = Text;
}
void IndentClass::Indent (int Amount) {
_Indent += Amount;
}
void IndentClass::SetIndent(int Amount) {
_Indent = Amount;
}
void IndentClass::ind (std::ostream& ofs) {
for (int i = 0;i < _Indent;i++) {
ofs << IndentText;
}
}
std::ostream& operator<< (std::ostream& ofs, IndentClass::Ind_t& ind) {
ind.state.ind(ofs);
return ofs;
}
std::ostream& operator<< (std::ostream& ofs, IndentClass::IndS_t& inds) {
inds.state.ind(ofs);
inds.state.Indent(1);
return ofs;
}
std::ostream& operator<< (std::ostream& ofs, IndentClass::IndE_t& inde) {
inde.state.Indent(-1);
inde.state.ind(ofs);
return ofs;
}
int main () {
IndentClass i;
std::cout << i.IndS << "test" << std::endl;
std::cout << i.Ind << "test" << std::endl;
std::cout << i.IndE << "test" << std::endl;
return 0;
}
Ideone Example
Related
I've seen examples that allow you to create a manipulator that inserts delimiters but none of those manipulators are sticky. That is, the manipulator returns a special class that inserts the delimiter, rather than modifying the output stream permanently so that it can do it on its own.
I want to be able to do this:
std::cout << sep(", ");
std::cout << "hello" << "world";
// "hello, world"
At the moment this prints "h, e, l, l, o, w, o, r, l, d" when I need it to be "hello, world". The reason I'm getting the wrong output is because I put the printing in the overflow() method and overflow() is being called for each character. I'm not sure where is the appropriate place to put it.
Sorry about it being verbose. If I knew a simpler way to write it I would. Just start from the bottom and work your way up:
#include <iostream>
#include <cstring>
// index for delimiter
int separator() {
static int idx = std::ios_base::xalloc();
return idx;
}
// index for storage of dynamically-allocated buffer
int rdbuffer() {
static int idx = std::ios_base::xalloc();
return idx;
}
struct custom_separator : std::streambuf {
public:
custom_separator(std::ostream& _stream)
: stream(_stream), buffer(_stream.rdbuf()) {}
int_type overflow(int_type c) {
// has a token been read already
if (token_read) {
char* delim = static_cast<char*>(stream.pword(separator()));
// print delim
buffer->sputn(delim, strlen(delim));
}
token_read = true;
return buffer->sputc(c);
}
private:
std::ostream& stream;
std::streambuf* buffer;
bool token_read = false;
};
// deletes the buffer and the delimiter
void cleanup(std::ios_base::event evt, std::ios_base& str, int idx) {
if (evt == std::ios_base::erase_event) {
delete static_cast<const char*>(str.pword(idx));
delete static_cast<custom_separator*>(str.pword(rdbuffer()));
}
}
std::ostream& set_separator(std::ostream& os, const char* str) {
if (!os.bad()) {
// If a separator string doesn't exist, assign os a buffer that prints one
if (!os.pword(separator())) {
auto buf = new custom_separator(os);
os.rdbuf(buf);
// this is to keep track of buf so we can delete it later
os.pword(rdbuffer()) = static_cast<void*>(buf);
os.register_callback(cleanup, separator());
}
// delete the previous separator
delete static_cast<const char*>(os.pword(separator()));
// store the new one
os.pword(separator()) = (void*)(str);
}
return os;
}
struct sep {
explicit sep(const char* _sep)
: separator(new char[strlen(_sep) + 1]) {
strcpy(separator, _sep);
}
sep(const sep&) = delete;
sep(const sep&&) = delete;
char* separator;
};
std::ostream& operator<<(std::ostream& os, const sep& manip) {
set_separator(os, manip.separator);
return os;
}
int main() {
std::cout << sep(", ");
std::cout << "hello";
std::cout << "world";
// "h, e, l, l, o, w, o, r, l, d"
}
The main issue with overflow() is that I don't know when to detect when the end of a token like "hello" has been read to know when to insert.
Try the following. Additionally, new line break processing (new line symbol) has been added so that the separator is not added during the transfer (after new line).
#include <iostream>
class MyStream
{
public:
struct Sep
{
Sep (const std::string& sep_value = ""):
m_sep(sep_value)
{
}
operator std::string()
{
return m_sep;
}
private:
std::string m_sep;
};
MyStream& operator << (const Sep& sep)
{
m_sep = sep;
m_add_sep = false;
return *this;
}
MyStream& operator << (const std::string& str)
{
if(str.find(MyStream::endl) != std::string::npos)
m_add_sep = false;
operator<< <std::string>(str);
m_add_sep = false;
return *this;
}
template <typename T>
MyStream& operator << (const T& value)
{
if(m_add_sep)
std::cout << static_cast<std::string>(m_sep);
std::cout << value;
m_add_sep = true;
return *this;
}
static const std::string endl;
private:
Sep m_sep;
bool m_add_sep = false;
};
const std::string MyStream::endl = std::string("\n");
int main()
{
MyStream stream;
stream << "hello" << "world" << MyStream::endl; // prints "helloworld"
stream << MyStream::Sep(", ");
stream << "hello" << "world" << MyStream::endl; // prints "hello, world"
stream << 1 << 2;
stream << 3 << MyStream::endl; // both lines prints "1, 2, 3"
stream << MyStream::Sep();
stream << 1 << 2 << 3 << MyStream::endl; // prints "123"
return 0;
}
Here's a possible solution. The separator is the same for all streams.
namespace alt_std
{
struct sep
{
sep(const char* s) { s_ = s; }
friend std::ostream& operator<<(std::ostream& os, const sep& sm)
{
return os;
}
inline static std::string s_{};
};
std::ostream& operator<<(std::ostream& os, const char* s)
{
return std::operator<<(os, s), std::operator<<(os, sep::s_);
}
}
int main()
{
using namespace alt_std;
std::cout << sep(" ") << "hello";
std::cout << "world" << std::endl; // "hello world\n"
std::cout << sep("") << "hel" << "lo"; // "hello"
}
If you want to do it at the stream object level, it's more difficult because stream objects don't have a custom storage space where you can store the value of the separator.
Or you could simply wrap the stream object:
template< typename OS >
struct wrapper
{
wrapper(OS& os, const char* sep) : os_{ os }, sep_{ sep } {}
template< typename T>
friend wrapper& operator<<(wrapper& os, const T& v)
{
os.os_ << v << os.sep_;
return os;
}
OS& os_;
std::string sep_;
};
int main()
{
wrapper os{ std::cout, " " };
os << "hello" << "world";
}
Sorry if this question has been asked before, but I'm struggling with overloading the << operator to stream different data into multiple files.
I have a Player class, which has the following attributes:
char* name;
char* password;
int hScore;
int totalGames;
int totalScore;
int avgScore;
I want to overload the << operator twice: one to stream the name, password and hScore to a "Players.txt" file, and a second overload to stream the totalGames, totalScore and avgScore to a different .txt file which is based off each player's name, e.g. "Player1.txt".
Here's what my operator looks like in the Player class:
friend ostream& operator<< (std::ostream& os, Player& player)
{
os << player.name << "\n" << player.encryptPassword((player.password), 3) << "\n" << player.hScore << "\n";
return os;
}
And here's where I am calling it, from a PlayerLibrary class which contains a vector of Players:
ofstream out("Yahtzee.txt");
if (out.is_open())
{
for_each(playerList.begin(), playerList.end(), [&out](Player* player) {out << (*player);});
}
else
{
cout << "THERE WAS AN ERROR WRITING TO FILE\n";
}
Basically, I want to stream the other variables into another file which is named after the player name, and contains a scorecard for each game they've played. So far it looks like:
for (auto it = playerList.begin(); it != playerList.end(); ++it)
{
auto position = it - playerList.begin();
string filename(playerList[position]->getName());
filename = filename + ".txt";
ofstream out2(filename);
for (int i = 0; i < playerList[position]->getNumberOfScorecards(); i++)
{
out2 << *playerList[position]->getScorecard(i);
}
}
This only streams the scorecard and not the totalGames, totalScore and avgScore, like I want it to.
I have tried just moving those variables into the scorecard class, but I feel that it makes more sense to have them where they are.
I understand that I can't overload operator<< twice if both overloads have the same parameters, is there another way of going about this? Is there anyway perhaps in the overloaded function to use the output stream and check the name of the .txt file or something.
Hope the question makes sense.
Rather than defining an operator<< for Player itself, create a couple of utility types that refer to the Player and have their own operator<<s, let them decide which portions of the Player to stream, eg:
class Player
{
private:
std::string name;
std::string password;
int hScore;
int totalGames;
int totalScore;
int avgScore;
...
public:
...
std::string getName{} const { return name; }
...
std::string EncryptPassword(int arg) const { return ...; }
int getNumberOfScorecards() const { return ...; }
Scorecard* getScorecard(int index) const { return ...; }
class Info
{
const Player &m_player;
void print(std::ostream &os) const {
os << m_player.name << "\n" << m_player.encryptPassword(3) << "\n" << m_player.hScore << "\n";
}
public:
Info(const Player &player) : m_player(player) {}
friend std::ostream& operator<<(std::ostream &os, const Info &info)
{
info.print(os);
return os;
}
};
friend class Info;
struct Stats
{
const Player &m_player;
void print(std::ostream &os) const
{
os << m_player.totalGames << "\n" << m_player.totalScore << "\n" << m_player.avgScore << "\n";
}
public:
Stats(const Player &player) : m_player(player) {}
friend std::ostream& operator<<(std::ostream &os, const Stats &stats)
{
stats.print(os);
return os;
}
};
friend class Stats;
};
And then you can use them like this:
ofstream out("Yahtzee.txt");
if (out.is_open())
{
for(auto *player : playerList)
out << Player::Info(*player);
}
else
{
cout << "THERE WAS AN ERROR WRITING TO FILE\n";
}
for (auto *player : playerList)
{
ofstream out2(player->getName() + ".txt");
out2 << Player::Stats(*player);
for (int i = 0; i < player->getNumberOfScorecards(); ++i)
{
out2 << *player->getScorecard(i);
}
}
Online Demo
I have something like this where Client and Order are classes :
std::vector<std::pair<Client,Order>> pair;
pair.push_back(std::make_pair(Client(2,"Anca"),Order(3,1)));
pair.push_back(std::make_pair(Client(16,"Maria"),Order(1,3)));
pair.push_back(std::make_pair(Client(29,"Alex"),Order(10,5)));
class Client{
private:
int dateWhenOrderWasPlaced;
std::string clientName;
public:
Client(int date,std::string name){
dateWhenOrderWasPlaced=date;
clientName=name;
}
class Order{
private:
int amountPizza;
int pizzaAge;
public:
Order(int amPizza,int agePizza){
amountPizza=amPizza;
pizzaAge=agePizza;
}
And i can't figure out how to print this.I have tried in many ways :
void print(std::vector<std::pair<Client,Order>> pair){
for(const auto& it : pair){
std::cout << "First: "<<pair[it].first<< ", Second: " << pair[it].second <<std::endl;
}
}
And this :
void print(std::vector<std::pair<Client,Order>> pair){
for(const auto& it : pair){
std::cout << "First: "<<it.first<< ", Second: " << it.second <<std::endl;
}
}
And in the both ways i have error(first-no operator[] and second,no operator <<)
Your first attempt does not work because it is the actual pair but std::pair does not have an operator[]. Your second attempt is the correct way to go, but it does not work because you have not defined operator<< for your classes.
So, simply define operator<<, eg:
class Client
{
private:
int dateWhenOrderWasPlaced;
std::string clientName;
public:
Client(int date, std::string name)
: dateWhenOrderWasPlaced(date), clientName(name)
{
}
friend std::ostream& operator<<(std::ostream &os, const Client &c)
{
// print c.dateWhenOrderWasPlaced and c.clientName to os as needed...
return os;
}
};
class Order
{
private:
int amountPizza;
int pizzaAge;
public:
Order(int amPizza, int agePizza)
: amountPizza(amPizza), pizzaAge(agePizza)
{
}
friend std::ostream& operator<<(std::ostream &os, const Order &o)
{
// print o.amountPizza and o.pizzaAge to os as needed...
return os;
}
};
void print(const std::vector<std::pair<Client,Order>> &pair)
{
for(const auto& it : pair)
{
std::cout << "First: " << it.first << ", Second: " << it.second << std::endl;
}
}
I have 2 classes, I make an object from the second class (I pass the filename as an argument). It should print the contents of the file which contains the following data in the following format:
A.Yordanov 1234567819
S.Todorov 3456789120
D.Lazarov 2569789054
P.Pavlov 4329549823
M.Kalinova 2367892343
B.Georgiev 659045324
I have overloaded the << operator but I when I try to cout << cty2 nothing appears on the console even though I have put the file in the same directory?
// OOP_Homework.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <iostream>
#include <fstream>
#include <set>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
fstream f;
class CPerson {
string name;
string egn;
public:
CPerson(string n, string e) {
name = n;
egn = e;
}
friend bool operator<(CPerson p1, CPerson p2) {
if (p1.egn < p2.egn) {
return true;
}
return false;
}
friend bool operator==(CPerson p1, CPerson p2) {
if (p1.egn == p2.egn) {
return true;
}
return false;
}
friend ostream& operator<< (ostream o, CPerson pn) {
o << "Egn" << endl;
o << pn.egn << endl;
o << "Name:" << endl;
o << pn.name << endl;
}
friend istream& operator>> (istream is, CPerson p) {
is >> p.egn;
is >> p.name;
return is;
}
string getName() {
return name;
}
string getEgn() {
return egn;
}
void setName(string n) {
name = n;
}
void setEgn(string e) {
egn = e;
}
};
class CCity {
vector<CPerson> pr;
public:
CCity(string fl) {
f.open(fl, ios::out);
string name = "", fn = "";
while (!f.eof()) {
//формата на данните във файла е във вида:
//<име на студент> <факултетен номер>
cin >> name >> fn;
pr.push_back(CPerson(name, fn));
}
f.close();
}
//помощен getter за вектора pr;
vector<CPerson> getV() {
return pr;
}
friend ostream& operator<<(ostream& os, CCity& psn) {
vector<CPerson> ps = psn.getV();
for (auto x = ps.begin(); x != ps.end(); x++) {
os << x->getName() << endl;
os << x->getEgn() << endl;
}
return os;
}
vector<CPerson> getDuplicate() {
set<CPerson> temp;
vector<CPerson> duplicates;
for (auto i = pr.begin(); i != pr.end(); i++) {
for (auto x : pr) {
if (*i == x) {
temp.insert(*i);
}
}
}
for (auto j : temp) {
duplicates.push_back(j);
}
temp.clear();
//връщаме студентите с повтарящи се егн-та
return duplicates;
}
void removeDuplicates() {
sort(pr.begin(),pr.end());
pr.erase(unique(pr.begin(), pr.end()));
}
void removeVector(vector<CPerson> ob) {
for (auto i:ob) {
for (auto x = pr.begin(); x != pr.end(); x++) {
if (i == *x) {
pr.erase(x);
}
}
}
}
};
int main()
{
CCity cty2("persons.txt");
//cout << cty1 << endl;
cout << cty2 << endl;
return 0;
}
The code for your overload for operator<< should be
friend ostream& operator<< (ostream &o, const CPerson &pn) {
// ^ ^^^^^ ^
o << "Egn" << endl;
o << pn.egn << endl;
o << "Name:" << endl;
o << pn.name << endl;
return o; // since return type is ostream&
}
You should be passing the stream by reference and returning it once you've finished using it. Passing by-reference ensures that the same stream is used (unlike pass-by-value).
Another thing to note would be your CPerson p function arguments. These should be passed by-reference as well. With operator<<, your CPerson won't be modified, so we can keep it as const.
You may also want to watch out your operator>>. Again, istream is should be istream &is. With the CPerson p parameter, you will modify it, so you'll definitely want to be passing it as a reference.
friend istream& operator>> (istream &is, CPerson &p) {
// ^ ^
is >> p.egn;
is >> p.name;
return is;
}
In your other overloads, you should be using const CPerson &p as well. Moreover, your overloads for operator< and operator== don't need to be friended since they're not accessing any other class's private members. Thus,
bool operator<(const CPerson &p1, const CPerson &p2) {
if (p1.egn < p2.egn) {
return true;
}
return false;
}
bool operator==(const CPerson &p1, const CPerson &p2) {
if (p1.egn == p2.egn) {
return true;
}
return false;
}
You'll want to get used to passing your classes by-reference as it saves space (not having to copy-construct another instance of the class as passing by-value would do). It's thus, more efficient both space-wise and performance-wise to pass your classes by reference.
Here are my header files:
//Frame.h
#pragma once
class Frame {
string frameName;
protected:
double fileSize;
vector<Attribute> attributes;
public:
Frame(string f, double size, vector<Attribute> d) :frameName(f), fileSize(size), attributes(d) {}
virtual ~Frame() {}
string& GetFrameName() { return frameName; }
Attribute& operator[](int);
int size() { return attributes.size(); }
virtual void Compress() = 0;
friend ostream& operator<<(ostream&, Frame&);
};
// AudioFrame
#pragma once
class AudioFrame :public Frame {
static const int RATES = 3;
static constexpr double BITRATE[]{128,160,192};
static constexpr double COMPRESSION_RATIO[]{11.1,9.1,7.1};
public:
AudioFrame(string frameName, double fileSize, vector<Attribute> d) :Frame(frameName,fileSize, d) {}
~AudioFrame(){}
void Compress();
friend ostream& operator<<(ostream&, AudioFrame&);
};
//ImageFrame.h
#pragma once
class ImageFrame :public Frame {
static const int BITS = 8;
static constexpr double COMPRESSION_RATIO = 6.0;
static constexpr double BITDEPTH_FACTOR[] {11.1,4.6,3.5,2.4,1.9,1.5,1.2,1.0};
public:
ImageFrame(string fileName, double fileSize, vector<Attribute> d) :Frame(fileName, fileSize, d) {}
~ImageFrame(){}
void Compress();
friend ostream& operator<<(ostream&, ImageFrame&);
};
Each one of them have a **friend ostream& operator<<(ostream&, ImageFrame&);**
But when i do this
ImageFrame test;
cout << test << endl;
Only Frame class's operator << is called. Any solution to this?
Also, professor doesn't want me to change anything from the header files!
EDIT:
here is how i implement the operator <<:
// code from AudioFrame.cpp
ostream& operator<<(ostream& os, AudioFrame& obj) {
os << "AudioFrame" << endl;
os << "Name = " << obj.GetFrameName() << endl;
for (unsigned int i = 0; i < obj.attributes.size(); i++) {
os << "\tBandwidth #" << i << ": " << obj.attributes[i] << endl;
}
return os;
}
// code from ImageFrame.cpp
ostream& operator<<(ostream& os, ImageFrame& obj) {
os << "ImageFrame" << endl;
os << "Name = " << obj.GetFrameName() << endl;
for (unsigned int i = 0; i < obj.attributes.size(); i++) {
os << "\tResolution #" << i << ": " << obj.attributes[i] << endl;
}
return os;
}
// code from Frame.cpp
ostream& operator<<(ostream& os, Frame& obj) {
return os;
}
But when i run the test code, only the code from Frame.cpp is run.
EDIT2:
So i feel like i should also share my real test code:
int type;
deque<Frame*> frames; // all frames are stored here
// user is promoted a console menu for selecting a frame type (ImageFrame or AudioFrame)
if (type == 1)
frames.push_back(new AudioFrame(...));
else
frames.push_back(new ImageFrame(...));
// now when i need to print all frames i do
for (unsigned int i = 0; i < frames.size(); i++)
cout << *(frames[i]) << endl;
If you REALLY want cout << *(frames[i]) << endl; to dispatch polymorphically, and you REALLY cannot alter the headers, then you have no choice but to rely on dynamic typing.
ostream& operator<<(ostream& stream, Frame& frame) {
AudioFrame* as_audio_frame = dynamic_cast<AudioFrame*>(&frame);
ImageFrame* as_image_frame = dynamic_cast<ImageFrame*>(&frame);
if(as_audio_frame) {
return stream << *as_audio_frame;
}
if(as_image_frame) {
return stream << *as_image_frame;
}
//normal frame code
}
However, this is TERRIBLE code, and signals that some reorganizing is severely needed in the headers. So i suspect there is something wrong in your intrepretation of your assignment.
Edit, well, actually, there is a hilariously overengineered alternative...
class FrameAdapterInterface {
public:
virtual ~FrameAdapterInterface() {};
protected:
virtual std::ostream print(std::ostream&) = 0;
friend ostream& operator<<(ostream&, FrameAdapterInterface &);
};
template<typename FRAME_T>
class AdapatedFrameType : public FrameAdapterInterface {
FRAME_T data_;
public:
template<typename... ARGS_T>
AdapatedFrameType(ARGS_T&&... args)
: data_(std::forward<ARGS_T>(args)...) {}
ostream& print(std::ostream& stream) override {
return stream << data_;
}
};
ostream& FrameAdapterInterface::operator<<(ostream& stream, FrameAdapterInterface& frame) {
return frame.print(stream);
}