0

After reading this: C++ Writing to file and Console Output at the same time with simple code , I am trying to write a function to handle what I have in the for-loop. But I don't know how to pass a piece of code like this :setw(3) << right << get<0>(*it_party) << setw(9) << "" altogether as an argument into a function so that both cout and file can use it.

The helper function I am trying to write:
void print(std::ostream &os1, std::ostream &os2, const [I don't know what to put in here])
{
    os1 << the argument; // cout
    os2 << the argument; // file
}

ofstream file;
file.open("test.txt");

for (auto it_party = parties_.begin(); it_party != parties_.end(); ++it_party) {
    cout << setw(3) << right << get<0>(*it_party) << setw(9) << "";
    file << setw(3) << right << get<0>(*it_party) << setw(9) << "";
    cout << setw(7) << left << get<1>(*it_party) << setw(1) << "";
    file << setw(7) << left << get<1>(*it_party) << setw(1) << "";
    ...
    ...
  }
nkforce
  • 29
  • 2
  • 9

3 Answers3

3

If you want to string outputs together like that, you'll probably find it easier to use some kind of "tee" class:

class Tee {
private:
    std::ostream &os1, &os2;
public:
    Tee(std::ostream &os1, std::ostream &os2) : os1(os1), os2(os2) { }

    template <typename T>
    Tee& operator<<(const T &thing) {
        os1 << thing;
        os2 << thing;
        return *this;
    }
};

This'll take a template argument, so it won't care whether you're passing right or setw(3). You can use it like:

Tee t(std::cout, std::cout);
t << setw(10) << "right" << " Thing" << setw(9);
scohe001
  • 15,110
  • 2
  • 31
  • 51
0

You can easily do this using std::stringstream. I don't know what get<>() is but here is a basic example:

#include <string>  
#include <iostream> 
#include <sstream>   
#include <fstream>

void fn(std::string output) {

    std::ofstream file("file.txt");

    std::cout << output;
    file << output;

}

int main() {

    std::stringstream buffer;
    buffer << "some random text" << std::endl;

    fn(buffer.str());

    return 0;
}
DimChtz
  • 4,043
  • 2
  • 21
  • 39
0

Unfortunately, you cannot pass all that stuff as only one argument. But there are some advanced techniques, that can help you, such as variadic templates and C++17 fold expressions.

Variadic templates are a feature that allows you, for example, to pass an unknown at compile-time amount of arguments of different types. You can see some examples of such in a standard library, such as std::tuple.

Fold expressions are yet another feature used in combination with the former one. It allows you to write pretty simple variadic-templated code:

template<typename ...Args>
void printer(const Args &... args) {
    (std::cout << ... << args) << '\n';
}

Here we see a function, that takes some const & to some arguments (we don't know their count or distinct types), but we have such fancy thing as args, a parameter pack, that represents our arguments, and Args as their types "packed" together;

You can use that to pass arbitrary arguments to your streams:

template<typename ...Args>
void printer(const Args &... args) {
    (std::cout << ... << args);
    (file << ... << args);
}

There are some other things to improve in this solution, such as perfect forwarding, but these are for further study.

Yuri Kovalenko
  • 1,325
  • 9
  • 19