使用std :: vector <char>作为变体</char>

时间:2011-08-16 20:44:21

标签: c++

我想要一个带

的简单变体
  • 最小开销
  • 可以传递给用C语言编写的函数

所以我决定使用像这样的std :: vector

typedef std::vector<char> SimpleVariant;
SimpleVariant data;

(1)存储std :: string

for(std::string::iterator it = str.begin(); it != str.end(); ++it)
    {
        data.push_back( *it );
    }
    data.push_back('\0');

(2)存储双重

data.resize(64);
std::sprintf(&data[0], "%.*g", 20, val);

(3)得到一个字符串

std::string str = std::string( m_data.begin(), m_data.end() );

(4)获得双重

double dbl = boost::lexical_cast<double>(&data[0]);

根据我的要求,这是一种合理的方法吗?是否有轻量级变体,我可以使用而不是试图重新发明轮子?
我知道boost :: variant和boost ::任何它们对我的需求都太重了

3 个答案:

答案 0 :(得分:5)

  

可以传递给用C语言编写的函数

C ++中没有可敬的变体是C兼容的,除了将指针作为void *传递给它并提供可能操作它的函数。 C变体保证是非类型安全的,而C ++变体保证其类型。您所能做的就是存储类型枚举和与最大大小相对应的内存块。

此外,boost::any并不比vector更重要。你只是重新实现它。以较低效的方式。并且安全性较低。

答案 1 :(得分:1)

将数据的文本表示序列化为动态分配的内存几乎不能被视为最小开销。然后,关于C函数,您想要将变量传递给C函数到底是什么,您是否只想传递变量?你打算在C函数中使用数据吗?

如果您只想通过C代码传递变量(但不在那里使用它),那么考虑使用boost :: variant或boost :: any并传递void*,如果您打算使用里面的数据C,我建议使用带有标记的结构来标识类型,并使用足够大的数组来保存要存储的数据,然后将值转换为该数组。

答案 2 :(得分:0)

您还没有真正提供有关C接口如何工作的大量信息。所以这个建议可能没有帮助。但是,假设您有一个如下所示的C接口:

int GetAValue(void *data, int size); //Returns the type of data stored in the data pointer. Will not write past size.
void DoSomethingWithValue(int type, void *data, int size); //Gives data to C, to do something with. Does not modify it.
void ModifyValue(int type, void *data, int size); //Gives data to C, where it modifies it.

我会使用boost :: variant,如下所示:

typedef boost::variant<int, double, std::string> MyVariant;

struct DoSomethingWithValueVisit : public boost::static_visitor<>
{
  void operator()(int val)
  {
    DoSomethingWithValue(TYPE_INTEGER, &val, sizeof(int));
  }

  void operator()(double val)
  {
    DoSomethingWithValue(TYPE_DOUBLE, &val, sizeof(double));
  }

  void operator()(const std::string &val)
  {
    DoSomethingWithValue(TYPE_STRING, (void*)val.c_str(), val.size() + 1);
  }
};

struct ModifyValueVisit : public boost::static_visitor<>
{
  void operator()(int &val)
  {
    ModifyValue(TYPE_INTEGER, &val, sizeof(int));
  }

  void operator()(double &val)
  {
    ModifyValue(TYPE_DOUBLE, &val, sizeof(double));
  }

  void operator()(std::string &val)
  {
    char buffer[128];
    strncpy(buffer, val.c_str(), 127);
    ModifyValue(TYPE_STRING, buffer, 128);
    val = buffer;
  }
};

MyVariant GetAValueFromC()
{
  char buffer[128];
  int type = GetAValue(buffer, 128);

  switch(type)
  {
  case TYPE_INTEGER:
    return *reinterpret_cast<int*>(&buffer[0]);
  case TYPE_DOUBLE:
    return *reinterpret_cast<double*>(&buffer[0]);
  case TYPE_STRING:
    return std::string(buffer);
  }
}

int main()
{
  MyVariant value = GetAValueFromC();
  //Non-modifying
  boost::apply_visitor(DoSomethingWithValueVisit(), value);
  //Modifying
  boost::apply_visitor(ModifyValueVisit(), value);
}

根据需要随意为变体添加更多类型。