C++ 如何将类模板参数传递给boost::variant?
我有一个使用boost::get of boost:variant模块的模板方法:C++ 如何将类模板参数传递给boost::variant?,c++,templates,boost,C++,Templates,Boost,我有一个使用boost::get of boost:variant模块的模板方法: typedef boost::variant<int, std::string, bool, uint8_t> Variant; template <class T> void write(const Variant& t) { size_t sizeT = boost::apply_visitor(SizeOfVisitor(), t); memcpy(&
typedef boost::variant<int, std::string, bool, uint8_t> Variant;
template <class T>
void write(const Variant& t) {
size_t sizeT = boost::apply_visitor(SizeOfVisitor(), t);
memcpy(&v[offset], &boost::get<T>(t), sizeT);
}
编辑:如果您知道实现所需结果的任何其他方法-实际获取boost::variant内部变量的地址,从那里复制,请与我分享您的想法
谢谢您开关(m_var.which()){//返回类型的int索引,索引顺序为传递的模板类
switch (m_var.which()) { // Returns an int index of types in the order of passed template classes
case 0: // This is int
Writer.write<int>(m_var);
break;
case 1: // This is std::string
Writer.write<std::string>(m_var);
break;
...
}
案例0://这是int
Writer.write(m_var);
打破
案例1://这是std::string
Writer.write(m_var);
打破
...
}
:)我碰巧在这里写了一个非常相似的答案:
memcpy
完全是假的(因此不能将其与std::string
一起使用)
对只有在运行时才知道类型的variant
s进行操作的方法是使用boost::static\u visitor
下面是一个例子,其中main()
经过调整,非常接近您想要实现的目标
#包括
#包括
#包括//仅作为示例
#包括
命名空间序列化{
命名空间自定义{
模板
void do_序列化(T const&x,Out&Out)
{
静态断言(boost::is_pod(),“”);
char const*rawp=reinterpret_cast(&x);
标准:复制(rawp,rawp+sizeof(T),输出);
}
模板
void do_序列化(std::string const&x,Out&Out)
{
不序列化(x.size(),out);
用于(自动通道:x)
do_序列化(ch,out);
}
}
结构序列化\u f:public boost::static\u visitor{
模板
void运算符()(boost::variant const&v,Out&Out)const
{
boost::apply_visitor(boost::bind(*this,_1,boost::ref(out)),v);
}
模板
void运算符()(T常量和x,Out和Out)常量
{
使用customization::do_serialize;//ADL分派
dou序列化(x,out);
}
};
模板
输出序列化(T常量和v,输出){
常量静态序列化_f_vis{};
_vis(v,out);
返回;
}
}
名称空间MyUserTypes{
结构A{
std::字符串名;
int i;
};
模板void do_serialize(const&v,Out&Out){//ADL将发现
序列化::序列化(v.name,out);
序列化::序列化(v.i,out);
}
}
int main(){
使用名称空间序列化;
std::矢量二进制数据;
自动输出插入器=返回插入器(二进制数据);
//变体和自定义类型
typedef boost::变量V;
MyUserTypes::A myA{“0123456789”,99};
V=boost::array();
序列化(myA,out\u插入器);
序列化(v,输出插入器);
v=myA;
序列化(v,输出插入器);
std::cout Haha:)这很有趣。但这不是我想写东西的地方。我正在用另一种方法写东西。@rightaway717解决方案是一样的,只需将开关移到你想进行分派的地方。在所有情况下,你都需要运行时分派方法,唯一的改进是有某种map这是将一个值映射到一个类型,比如一个boost::fusion::map
,但另一方面,我不确定这在理论上是否可行,所以我恐怕这是你能得到的最好的结果:)如果你要提倡切换魔法类型索引,为什么不同时提倡一些goto呢time@sehe这是我想到的最好的,以访客为基础的解决方案可能确实会更好,但也意味着更多的样板代码^^@Drax我很确定,如果他们将使用限制在c++14及以上,这是完全可能的。事实上,您已经可以完成管道设计并获得“多态性”仅使用c++11定义的内联访问者:请参阅。普通代码已经使用lambda中定义的本地结构,以减少命名空间混乱。有一个相关的变化。如果结果类型不匹配,仍然需要进行一些调整。您不能memcpy
一个std::string
值。我实际上没有使用它。对于字符串,我有一个单独的方法来memcpy它的内容(mystring.c_str())。我认为这是允许的,对吗?按照你问题中的代码设置方式,你会编写一个函数(错误地)memcpy
s一个std::string
应该接收一个std::string
-保持变量。你能解释一下boost::如何应用访问者(boost::bind(*this,_1,boost::ref(out)),v);
工作,访问者类的操作符()
是用T=具体类型(int,float等)调用的。我不明白替换是如何工作的。bind
函数后没有替换变量。我检查了boost手册,虽然这部分在文档中也不清楚。@rightaway717apply\u访问者
期望。它使用变量中包含的具体元素值调用该函子。现在,因为我们的函数n需要两个参数,我们将第二个参数绑定到ref(out)
,因此一元绑定函子仍然与apply\u visitor
兼容。
switch (m_var.which()) { // Returns an int index of types in the order of passed template classes
case 0: // This is int
Writer.write<int>(m_var);
break;
case 1: // This is std::string
Writer.write<std::string>(m_var);
break;
...
}
#include <boost/variant.hpp>
#include <boost/bind.hpp>
#include <boost/array.hpp> // just as a sample
#include <iostream>
namespace serialization {
namespace customization {
template<typename T, typename Out, typename R = typename boost::enable_if<boost::is_pod<T>, void>::type>
void do_serialize(T const& x, Out& out)
{
static_assert(boost::is_pod<T>(), "");
char const* rawp = reinterpret_cast<char const*>(&x);
std::copy(rawp, rawp+sizeof(T), out);
}
template<typename Out>
void do_serialize(std::string const& x, Out& out)
{
do_serialize(x.size(), out);
for(auto ch : x)
do_serialize(ch, out);
}
}
struct serialize_f : public boost::static_visitor<> {
template<typename Out, typename... T>
void operator()(boost::variant<T...> const& v, Out& out) const
{
boost::apply_visitor(boost::bind(*this, _1, boost::ref(out)), v);
}
template<typename T, typename Out>
void operator()(T const& x, Out& out) const
{
using customization::do_serialize; // ADL dispatch
do_serialize(x, out);
}
};
template <typename T, typename Out>
Out serialize(T const& v, Out out) {
const static serialize_f _vis {};
_vis(v, out);
return out;
}
}
namespace MyUserTypes {
struct A {
std::string name;
int i;
};
template<typename Out> void do_serialize(A const& v, Out& out) { // ADL will find this
serialization::serialize(v.name, out);
serialization::serialize(v.i, out);
}
}
int main() {
using namespace serialization;
std::vector<uint8_t> binary_data;
auto out_inserter = back_inserter(binary_data);
// variants and custom types
typedef boost::variant<MyUserTypes::A, boost::array<char, 42> > V;
MyUserTypes::A myA { "0123456789", 99 };
V v = boost::array<char,42>();
serialize(myA, out_inserter);
serialize(v, out_inserter);
v = myA;
serialize(v, out_inserter);
std::cout << "Bytes in binary_data vector: " << binary_data.size() << "\n";
}