How to declare an “implicit conversion” in a varia

2019-06-09 09:13发布

My aim is to send a data to several streams. It is possible by using boost::tee. But I want to write a wrapper with variadic template for using several streams.

The problem is that I need an implicit convertation from descendant struct to ancestor struct. Or something like that.

#include <boost/iostreams/tee.hpp>
#include <boost/iostreams/stream.hpp>
#include <fstream>
#include <iostream>
using namespace std;
namespace bio = boost::iostreams;
using bio::tee_device;
using bio::stream;

template<typename ... Ts> 
struct pu;

template<typename T1,typename T2> 
struct pu<T1,T2>:public stream<tee_device<T1,T2>> 
{
 typedef stream<tee_device<T1,T2>> base_type;
 operator base_type() { return static_cast<base_type&>(*this); }
 base_type& base = static_cast<base_type&>(*this);
 pu(T1& t1, T2& t2): base_type(tee_device<T1,T2>(t1,t2)) {}
};

template<typename T1,typename T2,typename T3,typename ... Ts>
struct pu<T1,T2,T3,Ts...> : public stream<tee_device<T1,pu<T2, T3, Ts ...>>> 
{
 typedef stream<tee_device<T1,pu<T2, T3, Ts ...>>> base_type;
 operator base_type() { return static_cast<base_type&>(*this); }
 pu(T1& t1, T2& t2, T3& t3, Ts& ... ts) : base_type(t2,t3,ts...){}
};

int main()
{
 pu<ostream,ostream> hT(cout,cout); hT<<"2";
 pu<ostream,ostream,ostream> hR(cout,cout,cout); hR<<"3";
 return 0;
}

The error is

 ..\boost_1_56_0\boost\iostreams\detail\forward.hpp|73|error: no matching function for call to 
'boost::iostreams::tee_device<std::basic_ostream<char>, pu<std::basic_ostream<char, std::char_traits<char> >, std::basic_ostream<char, std::char_traits<char> > > >::tee_device(std::basic_ostream<char>&, const std::basic_ostream<char>&)'|

The expected output is "22333". (I have "22", but have no "333". I.e. it's work well without the second line of main)

In other words, I need conversion from

template<typename T1,typename T2,typename T3,typename ... Ts>

to

stream<tee_device<T1,pu<T2, T3, Ts ...>>>

inside the template.

Thanks!

p.s. (it's my first post) && (i'm not native speaker)

1条回答
等我变得足够好
2楼-- · 2019-06-09 09:57

You already have the conversion that you ask for, because class types are already implicitly convertible to their public base types, but that is not what you need to solve the error.

The arguments to the base_type constructor in the variadic specialization of tu are wrong:

pu(T1& t1, T2& t2, T3& t3, Ts&... ts) : base_type(t2, t3, ts...) {}

You could try this instead:

pu(T1& t1, T2& t2, T3& t3, Ts&... ts) : base_type(t1, pu<T2, T3, Ts...>(t2, t3, ts...)) {}

But that won't work because, according to the documentation, if the arguments to the tee_device constructor are streams then they must bind to references to non-const, so they must be lvalues. The first argument t1 meets that criterion, but the second argument, a temporary pu, does not.

The following solution uses multiple inheritance to synthesize an lvalue pu:

template <typename T>
struct hold
{
    T held;
    template <typename... Ts> hold(Ts&&... vs) : held(std::forward<Ts>(vs)...) {}
};

template<typename...> 
struct pu;

template<typename T1, typename T2>
struct pu<T1, T2> : public stream<tee_device<T1, T2>> 
{
    typedef stream<tee_device<T1, T2>> base_type;
    pu(T1& t1, T2& t2): base_type(tee_device<T1, T2>(t1, t2)) {}
};

template<typename T1, typename T2, typename T3, typename... Ts>
struct pu<T1, T2, T3, Ts...> : private hold<pu<T2, T3, Ts...>>
                             , public stream<tee_device<T1, pu<T2, T3, Ts...>>> 
{
    typedef stream<tee_device<T1, pu<T2, T3, Ts...>>> base_type;
    pu(T1& t1, T2& t2, T3& t3, Ts&... ts) : hold<pu<T2, T3, Ts...>>(t2, t3, ts...)
                                          , base_type(t1, this->held) {}
};
查看更多
登录 后发表回答