Pawel Zubrycki非常好的回答(提到BjörnKarlsson的书)。
但代码以下行有几个误区:
// ...
o << *boost::any_cast<T>(a); // should be: o << *boost::any_cast<T>(&a);
// ...
a.streamer_->print(o, a); // should be: a.streamer_->print(o, a.o_);
这里的帕维尔Zubrycki的答案的修正版本(部分作品...)
#ifndef ANY_OUT_H
#define ANY_OUT_H
#include <iostream>
#include <boost/any.hpp>
struct streamer {
virtual void print(std::ostream &o, const boost::any &a) const =0;
virtual streamer * clone() const = 0;
virtual ~streamer() {}
};
template <class T>
struct streamer_impl: streamer{
void print(std::ostream &o, const boost::any &a) const { o << *boost::any_cast<T>(&a); }
streamer *clone() const { return new streamer_impl<T>(); }
};
class any_out {
streamer *streamer_;
boost::any o_;
void swap(any_out & r){
std::swap(streamer_, r.streamer_);
std::swap(o_, r.o_);
}
public:
any_out(): streamer_(0) {}
template<class T> any_out(const T& value)
: streamer_(new streamer_impl<T>()), o_(value) {}
any_out(const any_out& a)
: streamer_(a.streamer_ ? a.streamer_->clone() : 0), o_(a.o_) {}
template <class T>
any_out & operator=(const T& r) {
any_out(r).swap(*this);
return *this;
}
~any_out() { delete streamer_; }
friend std::ostream &operator<<(std::ostream& o, const any_out & a);
};
std::ostream &operator<<(std::ostream& o, const any_out & a) {
if(a.streamer_)
a.streamer_->print(o, a.o_);
return o;
}
#endif
这个测试代码的工作:
{
any_out a = 5;
std::cout << a << std::endl;
}
然而!!!!
下不不工作:
int main()
{
char str[] = "mystring";
any_out a = str;
std::cout << a << std::endl;
a = "myconststring";
std::cout << a << std::endl;
}
这里什么被打印出来。
为什么?
嘛类型是搞砸了,在下面的构造
any_out(const T& value)
如果我们再实例流光如
new streamer_impl<T>()
去除构造函数的引用,即
any_out(const T value)
...是一个解决方案。
另一种解决方法是保留引用并调整streamer_impl
的模板实例。见下面
这使作为对以下recommened解决方案是:
#ifndef ANY_OUT_H
#define ANY_OUT_H
#include <iostream>
#include <boost/any.hpp>
struct streamer {
virtual void print(std::ostream &o, const boost::any &a) const =0;
virtual streamer * clone() const = 0;
virtual ~streamer() {}
};
template <class T>
struct streamer_impl: streamer{
void print(std::ostream &o, const boost::any &a) const { o << boost::any_cast<T>(a); }
streamer *clone() const { return new streamer_impl<T>(); }
};
class any_out {
boost::any o_;
streamer *streamer_;
void swap(any_out & r){
std::swap(streamer_, r.streamer_);
std::swap(o_, r.o_);
}
public:
any_out(): streamer_(0) {}
template<class T> any_out(const T& value)
: o_(value),
#if 1
streamer_(new streamer_impl<typename std::decay<decltype(value)>::type>)
#else
streamer_((o_.type() == typeid(const char *))
? static_cast<streamer *>(new streamer_impl<const char *>)
: static_cast<streamer *>(new streamer_impl<T>))
#endif
{
}
// template<class T> any_out(const T value)
// : o_(value),
// streamer_(new streamer_impl<T>)
// {
// }
any_out(const any_out& a)
: o_(a.o_), streamer_(a.streamer_ ? a.streamer_->clone() : 0) {}
template <class T>
any_out & operator=(const T& r) {
any_out(r).swap(*this);
return *this;
}
~any_out() { delete streamer_; }
friend std::ostream &operator<<(std::ostream& o, const any_out & a);
};
std::ostream &operator<<(std::ostream& o, const any_out & a) {
if(a.streamer_)
a.streamer_->print(o, a.o_);
return o;
}
#endif
测试代码,给了上面的一些麻烦,现在可以很好地(用“特别建议的解决方案”):
int main()
{
char str[] = "mystring";
any_out a = str;
std::cout << a << std::endl;
a = "myconststring";
std::cout << a << std::endl;
}
谢谢帕维尔给我发送这个解决方案非常棒, –
Karlsson先生(本书的作者)非常出色。我只记得他的书中有解决这个问题的方法。我很高兴我能帮上忙。 –