简单结构的可变参数模板示例
Variadic template example for simple struct
我的目标是要输出多个流。您可以在下面看到工作代码。
我正在尝试使用可变参数模板,但我失败了。下一个代码怎么可能是"variaded"?
有几个非常相似的变量所以我想它可以使用可变参数模板重写,但我不知道如何。
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,但我的问题略有不同,可以在此处阅读:
好的,我得到了第二个工作,但我认为它没有多大意义:
#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 并将它们组合起来在你的习惯中 class.
您的代码的可变版本可能如下所示:
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;
}
我的目标是要输出多个流。您可以在下面看到工作代码。
我正在尝试使用可变参数模板,但我失败了。下一个代码怎么可能是"variaded"?
有几个非常相似的变量所以我想它可以使用可变参数模板重写,但我不知道如何。
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,但我的问题略有不同,可以在此处阅读:
好的,我得到了第二个工作,但我认为它没有多大意义:
#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 并将它们组合起来在你的习惯中 class.
您的代码的可变版本可能如下所示:
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;
}