#include <algorithm>
#include <iostream>
#include <vector>
#include <tuple>
#include <type_traits>
template<typename T>
struct IsOn
{
T *pt;
bool isOn;
IsOn(T& t, bool b):pt(&t), isOn(b) {}
};
template <typename ... Ts>
struct tmy
{
std::tuple<std::vector<IsOn<Ts>>...> vs;
};
namespace detail
{
template <typename T1, typename T2>
void print(std::vector<IsOn<T1>>& v, T2& t)
{
for (auto&& e : v) {
if (e.isOn) {
(*e.pt) << t;
}
}
}
template <std::size_t ... Is, typename Tuple, typename T>
void print(std::index_sequence<Is...>, Tuple& tuple, T& t)
{
int dummy[] = {0, (print(std::get<Is>(tuple), t), 0)...};
static_cast<void>(dummy); // avoid warning for unused variable
}
}
template<typename ...Ts, typename T>
tmy<Ts...>& operator<<(tmy<Ts...>& rt,T& t) {
detail::print(std::index_sequence_for<Ts...>{}, rt.vs, t);
return rt;
}
int main()
{
tmy<std::ostream, std::ostream> my;
std::get<0>(my.vs).push_back(IsOn<std::ostream>(std::cout, true));
std::get<0>(my.vs).push_back(IsOn<std::ostream>(std::cerr, false));
std::get<1>(my.vs).push_back(IsOn<std::ostream>(std::cout, true));
my<<"hi twice!";
}
I2luY2x1ZGUgPGFsZ29yaXRobT4KI2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8dmVjdG9yPgojaW5jbHVkZSA8dHVwbGU+CiNpbmNsdWRlIDx0eXBlX3RyYWl0cz4KCnRlbXBsYXRlPHR5cGVuYW1lIFQ+CnN0cnVjdCBJc09uCnsKICAgIFQgKnB0OwogICAgYm9vbCBpc09uOwogICAgSXNPbihUJiB0LCBib29sIGIpOnB0KCZ0KSwgaXNPbihiKSB7fQp9OwoKdGVtcGxhdGUgPHR5cGVuYW1lIC4uLiBUcz4Kc3RydWN0IHRteQp7CiAgICBzdGQ6OnR1cGxlPHN0ZDo6dmVjdG9yPElzT248VHM+Pi4uLj4gdnM7Cn07CgpuYW1lc3BhY2UgZGV0YWlsCnsKICAgIHRlbXBsYXRlIDx0eXBlbmFtZSBUMSwgdHlwZW5hbWUgVDI+CiAgICB2b2lkIHByaW50KHN0ZDo6dmVjdG9yPElzT248VDE+PiYgdiwgVDImIHQpCiAgICB7CiAgICAgICAgZm9yIChhdXRvJiYgZSA6IHYpIHsKICAgICAgICAgICAgaWYgKGUuaXNPbikgewogICAgICAgICAgICAgICAgKCplLnB0KSA8PCB0OwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQoKICAgIHRlbXBsYXRlIDxzdGQ6OnNpemVfdCAuLi4gSXMsIHR5cGVuYW1lIFR1cGxlLCB0eXBlbmFtZSBUPgogICAgdm9pZCBwcmludChzdGQ6OmluZGV4X3NlcXVlbmNlPElzLi4uPiwgVHVwbGUmIHR1cGxlLCBUJiB0KQogICAgewogICAgICAgIGludCBkdW1teVtdID0gezAsIChwcmludChzdGQ6OmdldDxJcz4odHVwbGUpLCB0KSwgMCkuLi59OwogICAgICAgIHN0YXRpY19jYXN0PHZvaWQ+KGR1bW15KTsgLy8gYXZvaWQgd2FybmluZyBmb3IgdW51c2VkIHZhcmlhYmxlCiAgICB9Cgp9Cgp0ZW1wbGF0ZTx0eXBlbmFtZSAuLi5UcywgdHlwZW5hbWUgVD4KdG15PFRzLi4uPiYgb3BlcmF0b3I8PCh0bXk8VHMuLi4+JiBydCxUJiB0KSB7CiAgICBkZXRhaWw6OnByaW50KHN0ZDo6aW5kZXhfc2VxdWVuY2VfZm9yPFRzLi4uPnt9LCBydC52cywgdCk7CiAgICByZXR1cm4gcnQ7Cn0KCmludCBtYWluKCkKewogICAgdG15PHN0ZDo6b3N0cmVhbSwgc3RkOjpvc3RyZWFtPiBteTsKICAgIHN0ZDo6Z2V0PDA+KG15LnZzKS5wdXNoX2JhY2soSXNPbjxzdGQ6Om9zdHJlYW0+KHN0ZDo6Y291dCwgdHJ1ZSkpOwogICAgc3RkOjpnZXQ8MD4obXkudnMpLnB1c2hfYmFjayhJc09uPHN0ZDo6b3N0cmVhbT4oc3RkOjpjZXJyLCBmYWxzZSkpOwogICAgc3RkOjpnZXQ8MT4obXkudnMpLnB1c2hfYmFjayhJc09uPHN0ZDo6b3N0cmVhbT4oc3RkOjpjb3V0LCB0cnVlKSk7CiAgICBteTw8ImhpIHR3aWNlISI7Cn0K