问题
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:
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) {}
};
来源:https://stackoverflow.com/questions/30524816/how-to-declare-an-implicit-conversion-in-a-variadic-template