Skip to main content
Bounty Ended with 25 reputation awarded by CommunityBot
added 1 character in body
Source Link
G. Sliepen
  • 61.7k
  • 3
  • 61
  • 152
template<typename... Ts>
class DataStorage {
public:
    DataStorage(Ts&&... streams): streamsstreams_(std::move(streams)...) {}

    void Store(const char *buffer, std::size_t count) {
        std::apply([=](Ts&... streams) {
            (streams.write(buffer, count), ...);
        }, streams_);
    }

    template<std::size_t I>
    auto& Get() {
        return std::get<I>(streams_);
    }

private:
    std::tuple<Ts...> streams_;
}
template<typename... Ts>
class DataStorage {
public:
    DataStorage(Ts&&... streams): streams(std::move(streams)...) {}

    void Store(const char *buffer, std::size_t count) {
        std::apply([=](Ts&... streams) {
            (streams.write(buffer, count), ...);
        }, streams_);
    }

    template<std::size_t I>
    auto& Get() {
        return std::get<I>(streams_);
    }

private:
    std::tuple<Ts...> streams_;
}
template<typename... Ts>
class DataStorage {
public:
    DataStorage(Ts&&... streams): streams_(std::move(streams)...) {}

    void Store(const char *buffer, std::size_t count) {
        std::apply([=](Ts&... streams) {
            (streams.write(buffer, count), ...);
        }, streams_);
    }

    template<std::size_t I>
    auto& Get() {
        return std::get<I>(streams_);
    }

private:
    std::tuple<Ts...> streams_;
}
added 939 characters in body
Source Link
G. Sliepen
  • 61.7k
  • 3
  • 61
  • 152
std::ofstream file("log.txt");
std::stringstream ss;

DataStorage ds({file, std::cout, ss});
ds.Store("Hello, world!\n", 14);

std::cout << "ss contains: " << ss.str();

Note that with this approach, you again only store references in the DataStorage class, making it store the concrete stream objects by value would be muchis more complicated, involving templates. It would look something like this:

template<typename... Ts>
class DataStorage {
public:
    DataStorage(Ts&&... streams): streams(std::move(streams)...) {}

    void Store(const char *buffer, std::size_t count) {
        std::apply([=](Ts&... streams) {
            (streams.write(buffer, count), ...);
        }, streams_);
    }

    template<std::size_t I>
    auto& Get() {
        return std::get<I>(streams_);
    }

private:
    std::tuple<Ts...> streams_;
}

An issue here is that you cannot copy C++ IO streams, you can only take a reference or move them. The above will work when you pass in new objects:

DataStorage ds(std::ofstream("log.txt"), std::stringstream{});
ds.write("Hello, world!\n", 14);
std::cout << "ss contains: " << ds.Get<1>().str();

But you cannot do this:

DataStorage ds(std::cout, ...);

At least not without adding further complications to the code.

std::ofstream file("log.txt");
std::stringstream ss;

DataStorage ds({file, std::cout, ss});
ds.Store("Hello, world!\n");

std::cout << "ss contains: " << ss.str();

Note that with this approach, you again only store references in the DataStorage class, making it store the concrete stream objects by value would be much more complicated, involving templates.

std::ofstream file("log.txt");
std::stringstream ss;

DataStorage ds({file, std::cout, ss});
ds.Store("Hello, world!\n", 14);

std::cout << "ss contains: " << ss.str();

Note that with this approach, you again only store references in the DataStorage class, making it store the concrete stream objects by value is more complicated, involving templates. It would look something like this:

template<typename... Ts>
class DataStorage {
public:
    DataStorage(Ts&&... streams): streams(std::move(streams)...) {}

    void Store(const char *buffer, std::size_t count) {
        std::apply([=](Ts&... streams) {
            (streams.write(buffer, count), ...);
        }, streams_);
    }

    template<std::size_t I>
    auto& Get() {
        return std::get<I>(streams_);
    }

private:
    std::tuple<Ts...> streams_;
}

An issue here is that you cannot copy C++ IO streams, you can only take a reference or move them. The above will work when you pass in new objects:

DataStorage ds(std::ofstream("log.txt"), std::stringstream{});
ds.write("Hello, world!\n", 14);
std::cout << "ss contains: " << ds.Get<1>().str();

But you cannot do this:

DataStorage ds(std::cout, ...);

At least not without adding further complications to the code.

added 950 characters in body
Source Link
G. Sliepen
  • 61.7k
  • 3
  • 61
  • 152

Going further

The above code works with all the stream types the standard library provides. But what if you need something not provided by the standard library, like writing to a POSIX file descriptor? In that case, you can implement your own custom stream class (see this question for some links). As long as it is or derives from std::ostream, it will then work with anything that can take a std::ostream.

It is also possible to turn your DataStorage class into something that inherits from std::ostream, so that you can do things like:

DataStorage ds(...);
ds << "Hello, world!\n";

And if the DataStorage class takes a list of std::ostreams in its constructor, but also is a std::ostream itself, you can write things like:

DataStorage ds1(...);
DataStorage ds2(...);
DataStorage ds({ds1, ds2});

Going further

The above code works with all the stream types the standard library provides. But what if you need something not provided by the standard library, like writing to a POSIX file descriptor? In that case, you can implement your own custom stream class (see this question for some links). As long as it is or derives from std::ostream, it will then work with anything that can take a std::ostream.

It is also possible to turn your DataStorage class into something that inherits from std::ostream, so that you can do things like:

DataStorage ds(...);
ds << "Hello, world!\n";

And if the DataStorage class takes a list of std::ostreams in its constructor, but also is a std::ostream itself, you can write things like:

DataStorage ds1(...);
DataStorage ds2(...);
DataStorage ds({ds1, ds2});
edited body
Source Link
G. Sliepen
  • 61.7k
  • 3
  • 61
  • 152
Loading
added 506 characters in body
Source Link
G. Sliepen
  • 61.7k
  • 3
  • 61
  • 152
Loading
added 61 characters in body
Source Link
G. Sliepen
  • 61.7k
  • 3
  • 61
  • 152
Loading
Source Link
G. Sliepen
  • 61.7k
  • 3
  • 61
  • 152
Loading