开发者

Using a std::vector<char> as a variant

I want a simple variant with

  • minimal overhead
  • that can be passed to functions written in the C language

so I decided to use a std::vector like this

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

(1) store a std::string

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

(2) store a double

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

(3) get a string

std::string str = std::s开发者_开发技巧tring( m_data.begin(), m_data.end() );

(4) get a double

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

Is this a reasonable approach given my requirements? Is there lightweight variant that I can use instead of trying to reinvent the wheel?

I am aware of boost::variant and boost::any they are too heavyweight for my needs


that can be passed to functions written in the C language

No respectable variant in C++ is C-compatible, beyond passing a pointer to it as void* and providing functions that might manipulate it. C variants are guaranteed to be non-type-safe, whereas C++ variants have their types guaranteed. All you can do is store a type enumeration and a block of memory corresponding to the maximum size.

Also, boost::any isn't more heavyweight than a vector. You're just re-implementing it. In a less efficient way. And less safely.


Serializing to the textual representation of the data into dynamically allocated memory can hardly be considered minimal overhead. And then again, regarding the C functions, what exactly do you want to pass the variant to the C functions for, do you want just to pass the variant through? do you intend on using the data inside the C functions?

If you only want to pass the variant through C code (but not use it there), then consider using boost::variant or boost::any and passing void*, if you intend on using the data inside C, I would recommend to use a structure with a tag to identify the type and an array big enough to hold the data you want to store and then cast the values into that array.


You haven't really given much information about how the C interface to this works. So this suggestion may not be helpful. But let's assume you have a C interface that looks like this:

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.

I would use a boost::variant as follows:

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);
}

Feel free to add more types to the variant as needed.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜