tags:

views:

190

answers:

3

Hi, I'm trying to do something like this,

enum Data_Property
{
 NAME,
 DATETIME,
 TYPE,
};

struct Item_properties
{
  char* Name;
  char* DateTime;
  int Type;  
};

int main() {  
std::string data = "/Name Item_Name /DATETIME [TimeStamp] /TYPE [Integer value]";
std::list <std::string> known_properties;

known_properties.push_back("/Name");
known_properties.push_back("/DATETIME");
known_properties.push_back("/TYPE");

Item_properties item_p = extract_properties(data); //I use a function to get properties
                                                   //in a structure.

//here I want to use a switch-case statement to get the property by enum value
}

I need to know is there any way i can make it any simple? or how would i combine property keys like (/NAME /DATETIME /TYPE) with an enum and avoid using a std::list i.e known_properties?

+3  A: 

As far as I know, there is nothing in C++ enums that is like C# enum attributes. I could be wrong though.

Given that, I'd suggest using a map to map the data property to item property. You should only have to build this map once. You can also associate the string representations to the item and data properties. This should make it easier to get the item properties objects built. I don't think a list would be an ideal data structure for this task.

Polaris878
+1  A: 

Have you looked at Boost::program_options? Here's some example code:

#include "boost\program_options\parsers.hpp"
#include "boost\program_options\variables_map.hpp"
#include <iostream>
using std::cout;
using std::endl;

namespace po = boost::program_options;

int _tmain(int argc, _TCHAR* argv[])
{

    po::options_description desc("Allowed options");
    string taskName;
    desc.add_options()
        ("help", "produce help message")
        ("TaskName", po::value<string>(&taskName), "The project's prefix")
    ;

    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, desc), vm);
    po::notify(vm);    

    if (vm.count("help")) {
        cout << desc << endl;
        return 1;
    }
    if (!vm.count("TaskName"))
    {
        cout << "Use \"DOTaskTests.exe --help\" for command line options" << endl;
        return 1;
    }
 }
David Gladfelter
+2  A: 

First, let me say that there is always another alternative, one of my philosophies.

Let's look at the Big Picture. You are trying read an Item from string. The Item is a container of datums. In Object Oriented terms, the Item would like each datum to load its own data from a string. The Item doesn't need to know how to load a datum, as it can request this from each datum.

Your datums are actually more complex and intelligent than the C++ simple POD types. (Simple POD types don't have field names.) So, you need to create classes to represent these (or to encapsulate the extra complexity). Trust me, this will be better in the long run.

Here is a simple example of Refactoring the Name member:

struct Name_Field
{
  std::string  value;  // Change your habits to prefer std:string to char *
  void load_from(const std::string& text,
                 const std::string::size_type& starting_position = 0)
  {
     value.clear();
     std::string::size_type position = 0;
     position = text.find("/Name", starting_position);
     if (position != std::string::npos) // the field name was found.
     {
         // Skip the next space
         ++position;

         // Check for end of text
         if (position < text.length())
         {
             std::string::size_t   end_position;
             end_position = text.find_first_not_of(" ", position);
             if (end_position != std::string::npos)
             {
                 value = text.substr(position, end_position - position);
             }
          }
      }
};

You can now add a load_from to the Item class:

struct Item
{
    Name_Field   Name;
    char *       DateTime;
    char *       Type;
    void load_from(const std::string& text)
    {
        std::string::size_t  position = 0;

        // Notice, the Name member is responsible for load its data,
        //    relieving Item class from knowing how to do it.
        Name.load_from(text, position);
    }
};

To load the item:

Item new_item;
new_item.load_from(data);

As you refactor, be aware of common methods. For example, you may want to put common methods between Name_Field and DateTime_Field into a base (parent) class, Field_Base. This will simplify your code and design as well as support re-usability.

Thomas Matthews
From another perspective, you could create *Loaders*, functions or objects that load datums. For example, a *Name Loader* would know how to extract a `Name` from a string.
Thomas Matthews
+1 for effort :)
Polaris878