【问题标题】:Variadic template example for simple struct简单结构的可变参数模板示例
【发布时间】:2015-05-31 11:42:57
【问题描述】:

我的目标是输出多个流。您可以在下面看到工作代码。

我正在尝试使用可变参数模板,但失败了。下一个代码如何“变化”?

有几个非常相似的变量,所以我猜它可以使用可变参数模板重写,但我不知道如何。

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

感谢您的尝试!

附言我知道存在 boost::tee,但我的问题略有不同,可以在这里阅读:How to declare an "implicit conversion" in a variadic template?

【问题讨论】:

  • 为什么你认为你需要一个可变参数模板来解决这个问题?我看不出采用这种方法的理由。
  • stringstreams 和 ofstreams 也是 ostreams。为什么需要几个不同的vector&lt;IsOn&lt;..&gt;&gt;
  • dyp,谢谢。出于学习目的,我想问:是否有一种常见且简单的方法来创建像“tmy”这样的结构,其中包含不同类型的可变数量的字段?
  • 是的,创建这种结构的一种常见且简单的方法是std::tuple

标签: c++ stream variadic-templates variadic


【解决方案1】:

好的,我得到了两个工作,但我认为它没有多大意义:

#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 并将它们组合到您的自定义类中。

【讨论】:

    【解决方案2】:

    您的代码的可变参数版本可能如下所示:

    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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-09-14
      • 1970-01-01
      • 2019-03-23
      • 2011-06-13
      • 1970-01-01
      • 2019-08-04
      • 2014-11-09
      • 2012-06-04
      相关资源
      最近更新 更多