Перенаправить вывод функции печати на консоль в строку

позволяет сказать, что у нас есть функция, которая печатает текст на консоли и в котором мы не имеем контроля над исходным кодом, но мы можем его назвать. Например

void foo() {
    std::cout<<"hello world"<<std::endl; 
    print_to_console(); // this could be printed from anything
}

Можно ли перенаправить вывод указанной выше функции в строку без изменения самой функции?

Я не ищу способ сделать это через терминал

Ответ 1

Да. Это можно сделать. Вот небольшая демонстрация:

#include <sstream>
#include <iostream>

void print_to_console() {
    std::cout << "Hello from print_to_console()" << std::endl;
}

void foo(){
  std::cout<<"hello world"<<std::endl; 
  print_to_console(); // this could be printed from anything
}
int main()
{
    std::stringstream ss;

    //change the underlying buffer and save the old buffer
    auto old_buf = std::cout.rdbuf(ss.rdbuf()); 

    foo(); //all the std::cout goes to ss

    std::cout.rdbuf(old_buf); //reset

    std::cout << "<redirected-output>\n" 
              << ss.str() 
              << "</redirected-output>" << std::endl;
}

Вывод:

<redirected-output>
hello world
Hello from print_to_console()
</redirected-output>

Смотрите онлайн-демонстрацию.

Ответ 2

@Андр спросил в комментарии моего первого ответа:

Что произойдет, если они используют printf, puts, write и т.д.? - Андре Костур

Для printf я придумал следующее решение. Он будет работать только на POSIX, поскольку fmemopen доступен только на POSIX, но вместо этого вы можете использовать временный файл, если хотите — это будет лучше, если вы хотите портативное решение. Основная идея будет такой же.

#include <cstdio>

void print_to_console() {
    std::printf( "Hello from print_to_console()\n" );
}

void foo(){
  std::printf("hello world\n");
  print_to_console(); // this could be printed from anything
}

int main()
{
    char buffer[1024];
    auto fp = fmemopen(buffer, 1024, "w");
    if ( !fp ) { std::printf("error"); return 0; }

    auto old = stdout;
    stdout = fp;

    foo(); //all the std::printf goes to buffer (using fp);

    std::fclose(fp);
    stdout = old; //reset

    std::printf("<redirected-output>\n%s</redirected-output>", buffer);
}

Вывод:

<redirected-output>
hello world
Hello from print_to_console()
</redirected-output>

Онлайн-демонстрация.

Ответ 3

class buffer
    : public std::streambuf
{
public:
    buffer(std::ostream& os)
        : stream(os), buf(os.rdbuf())
    { }

    ~buffer()
     {
         stream.rdbuf(buf);
     }

private:
    std::ostream& stream;
    std::streambuf* buf;
};

int main()
{
    buffer buf(std::cout);
    std::stringbuf sbuf;

    std::cout.rdbuf(sbuf);

    std::cout << "Hello, World\n";
}