2015-05-31 4 views
1

Моя цель состоит в том, чтобы выпустить несколько потоков. Вы можете увидеть рабочий код ниже.Пример шаблона Variadic для простой структуры

Я пытаюсь использовать вариативные шаблоны, но мне не удалось. Как следующий код может быть «изменен»?

Существует несколько очень похожих переменных, поэтому я предполагаю, что их можно переписать с использованием вариативных шаблонов, но я не знаю, как это сделать.

template<typename T> 
struct IsOn 
{ 
T *pt; 
bool isOn; 
IsOn(T& t, bool b):pt(&t),isOn(b) {} 
}; 

struct tmy 
{ 
vector<IsOn<ostream>> v0; 
vector<IsOn<ofstream>> v1; 
vector<IsOn<stringstream>> v2; 
}; 

template<typename T> 
tmy& operator<<(tmy& rt,T& t) { 
int len; 
len=rt.v0.size(); 
for(int i=0; i<len;++i) if(rt.v0[i].isOn) (*rt.v0[i].pt)<<t; 
len=rt.v1.size(); 
for(int i=0; i<len;++i) if(rt.v1[i].isOn) (*rt.v1[i].pt)<<t; 
len=rt.v2.size(); 
for(int i=0; i<len;++i) if(rt.v2[i].isOn) (*rt.v2[i].pt)<<t; 
return rt; 
} 


int main(int argc, char** argv) { 
tmy my; 
my.v0.push_back(IsOn<ostream>(cout, true)); 
my.v0.push_back(IsOn<ostream>(cerr, false)); 
my.v0.push_back(IsOn<ostream>(clog, true)); 
my<<"hi twice!"; 
} 

Спасибо за внимание!

p.s. Я знаю, что существует boost :: tee, но у меня есть немного другая проблема, которую можно прочитать здесь: How to declare an "implicit conversion" in a variadic template?

+0

Почему вы думаете, что нужно varadic шаблон для решения этой проблемы? Я не вижу причины такого подхода. –

+0

'stringstream' и 'ofstream' также являются 'ostream'. Зачем вам нужно несколько разных 'vector >'? – dyp

+0

dyp, спасибо. В целях изучения я хочу спросить: существует ли простой и простой способ создания структуры типа «tmy» с переменным количеством полей с другим типом? – ged

ответ

2

Хорошо, у меня есть две вещи, но я не думаю, что это имеет такой смысл:

#include <iostream> 

template<typename ... Streams> 
struct StreamCont 
{ 
}; 

template<typename Stream> 
struct StreamCont<Stream> 
{ 
    Stream & stream; 
    StreamCont(Stream & st) : stream(st) {}; 
}; 

template<typename Stream, typename ... Next> 
struct StreamCont<Stream, Next...> 
{ 
    Stream & stream; 
    StreamCont<Next...> next; 

    StreamCont(Stream & st, Next&... next) : stream(st), next(next...) {}; 
}; 

template<typename Stream, typename Arg> 
StreamCont<Stream>& operator<<(StreamCont<Stream> & str, Arg arg) 
{ 
    str.stream << arg; 
    return str; 
}; 

template<typename ... Streams, typename Arg> 
StreamCont<Streams...>& operator<<(StreamCont<Streams...> & str, Arg arg) 
{ 
    str.stream << arg; 
    str.next << arg; 
    return str; 
}; 

/* std::endl signature: 
template< class CharT, class Traits > 
std::basic_ostream<CharT, Traits>& endl(std::basic_ostream<CharT, Traits>& os); 

so this only works if all streams are equal 
*/ 

template<typename Stream> 
StreamCont<Stream>& operator<<(StreamCont<Stream> & str, Stream&(*func)(Stream&)) 
{ 
    func(str.stream); 
    return str; 
}; 


template<typename First, typename ... Streams> 
StreamCont<First, Streams...>& operator<<(StreamCont<First, Streams...> & str, First&(*func)(First&)) 
{ 
    func(str.stream); 
    str.next << func; 
    return str; 
}; 


int main() 
{ 
    StreamCont<std::ostream, std::ostream, std::ostream> 
     multi_stream(std::cout, std::cerr, std::clog); 

    multi_stream << 42 << std::endl; 
    return 0; 
} 

Это, вероятно, больше смысла делать то же самое с массивом, то есть:

#include <iostream> 
#include <array> 


template<typename Stream, size_t Size, typename Arg> 
std::array<Stream*, Size>& operator<<(std::array<Stream*, Size>& str, const Arg &arg) 
{ 
    for (auto s : str) 
     *s << arg; 
    return str; 
}; 

template<typename Stream, size_t Size> 
std::array<Stream*, Size>& operator<<(std::array<Stream*, Size>& str, Stream& (*func)(Stream&)) 
{ 
    for (auto s : str) 
     *s << func; 
    return str; 
}; 



int main() 
{ 
    std::array<std::ostream*, 3> strs = {&std::cout, &std::cerr, &std::clog}; 

    strs << 42 << std::endl; 
    return 0; 
} 

Надежда, что помогает, я не знаю, если вы могли бы быть лучше не писать пользовательские перегрузка ostream (см. boost.iostreams для этого) и просто используйте stream_bufs и объедините их в вас r пользовательский класс.

2

VARIADIC версия кода может выглядеть следующим образом:

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) 
    { 
#if 1 // Folding expression of C++17 
     (print(std::get<Is>(tuple, t)), ...); 
#else 
     int dummy[] = {0, (print(std::get<Is>(tuple, t)), 0)...}; 
     static_cast<void>(dummy); // avoid warning for unused variable 
#endif 
    } 

} 

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; 
} 

Live demo

 Смежные вопросы

  • Нет связанных вопросов^_^