converting from int to enum

后端 未结 4 1337
渐次进展
渐次进展 2021-01-20 08:31

I have declared the following enum :

  enum periods {one, five, ten, fifteen, thirty};

and now I want to pass it as a commandline argument

相关标签:
4条回答
  • 2021-01-20 09:14

    I have declared the following enum :

    enum periods {one, five, ten, fifteen, thirty};
    

    and now I want to pass it as a commandline argument in my main function.

    periods mp = atoi(argv[2]);   // simplified for answer...
    

    So, there are several issues:

    • you need to cast the int returned by atoi to the enum type... static_cast<periods>(...)
    • you should realise that an argv[2] of "0" will be mapped to the enumeration identifier "one", "1" will map to "five" etc...
      • if you actually want "1" to map to "one", "5" to "five" etc., the easiest way is to change your enum: enum periods { one = 1, five = 5, ten = 10, fifteen = 15, thirty = 30 };, but your example's obviously a little contrived so it's impossible to guess what will work best for your real needs
    • there's no validation

    You're better off creating a function:

    periods to_periods(const std::string& s)
    {
        if (s == "one") return one;
        if (s == "five") return five;
        if (s == "ten") return ten;
        if (s == "fifteen") return fifteen;
        if (s == "thirty") return thirty;
        throw std::runtime_error("invalid conversion from text to periods");
    }
    

    (When there are more cases, it's not uncommon to use a std::map or sorted std::vector to track these associations, and it allows reusable algorithms and the same data to support conversions from enum numeric value to textual identifier.)

    0 讨论(0)
  • 2021-01-20 09:15

    You have to explicitly cast it:

    mp=static_cast<periods>(atoi(min_prd.c_str()));
    
    0 讨论(0)
  • 2021-01-20 09:18

    At a random guess, what you really want is something more like:

    periods mp;
    if (argc < 2) {
        mp=one; // default value
    } else if (strcmp(argv[1], "one")==0) {
        mp=one;
    } else if (strcmp(argv[1], "five")==0) {
        mp=five;
    } else if (strcmp(argv[1], "ten")==0) {
        mp=ten;
    } else if (strcmp(argv[1], "fifteen")==0) {
        mp=fifteen;
    } else if (strcmp(argv[1], "thirty")==0) {
        mp=thirty;
    } else {
        fprintf(stderr, "I can't possibly comprehend periods = '%s'\n", argv[1]);
        return -1;
    }
    
    0 讨论(0)
  • 2021-01-20 09:20

    The straightforward solution is to use static_cast (as the other answer has already posted it):

    periods mp;
    if (argc == 2)
    {
       std::string min_prd(argv[1]); //the index should be 1
       mp = static_cast<periods>(atoi(min_prd.c_str()));
    }
    

    But then atoi should not be used to convert the c-string into int, because atoi doesn't check for error in the input string, hence it is unsafe.

    C++11 provides safer conversion functions, so you could use std::stoi as:

    try
    {
       periods mp;
       if (argc == 2)
       {
          //std::stoi could throw exception on error in input
          mp = static_cast<periods>(std::stoi(argv[1]));
       }
       //use mp here
    }
    catch(std::exception const & e)
    {
       std::cout << "exception caught with message : " << e.what() << std::endl;
    }
    

    Now that is a better solution.


    However, there is an alternative solution which you could use as:

    period mp;
    if (argc == 2)
    {
       mp = to_period(argv[1]); //how should we implement it?
       if (mp == period_end)
       {
           std::cout << "command line input error" << std::endl;
           return 0;
       }
    }
    

    Now the question is, how should we implement to_period function?

    Note that this solution assumes that the command line argument for enum value one would be its string representation, i.e it would be "one" instead of 1 which is integral representation.

    I would implement this solution as:

    • First create a header file called period_items.h as:

      //period_items.h
      E(one)
      E(five)
      E(ten)
      E(fifteen)
      E(thirty)
      
    • then create another header file called period.h as:

      //period.h
      #include <string>
      
      enum period 
      {
         #define E(item)  item,
           #include "period_items.h"
         #undef E
         period_end
      };
      
      period to_period(std::string const & name)
      {
         #define E(item)  if(name == #item) return item;
           #include "period_items.h"
         #undef E
         return period_end;
      }
      

    Now you can simply include period.h and use to_period function. :-)

    Note that in the alternative solution, I've used singular form rather than plural form, means I've used period rather than periods. I feel period is appropriate.

    You could also add this function to period.h as:

    std::string to_string(period value)
    {
        #define E(item)  if(value == item) return #item;
            #include "period_items.h"
        #undef E
        return "<error>";
    }
    

    Now, you could write this:

    #include "period.h"
    
    period v = to_period(argv[1)); //string to period
    std::string s = to_string(v);  //period to string
    

    Hope that helps.

    0 讨论(0)
提交回复
热议问题