How to assign a value to an enum based on input from a file in C++?

我只是一个虾纸丫 提交于 2020-01-04 14:24:08

问题


I have a file with values like: START and STOP. I also have the following enum declared:

enum Type {
    START,
    STOP
};

I'm trying to set the enum equal to the first value in the file with something like this:

enum Type foo;

ifstream ifile;
ifile.open("input.txt");

ifile >> foo;

I'm getting the error: no match for ‘operator>>’ in ‘ifile >> foo’.

How do I go about doing this correctly?


回答1:


The quickest thing to do is to read in an int and cast it to your Type enum.




回答2:


The stream insertion operator is not overloaded for user defined types. You can either define one for your enum object of type Type or use one of the existing overloads for reading unsigned char or bool and then change the value to your enum.




回答3:


http://condensedcpp.com/Enums.html

std::istream& operator >> (std::istream& i, Season& season)
{
    season = SPRING;
    std::string value;
    if (i >> value) {
        if (value == "Summer") {
            season = SUMMER;
        }
        else if (value == "Autumn") {
            season = AUTUMN;
        }
       else if (value == "Winter") {
            season = WINTER;
        }
    }
    return i;
}



回答4:


I've found for my particular situation that the following code is the best solution:

template <class T> T a2e(string c, const string a[], const int size) {
    for (int i=0; i < size; i++) {
        if (c == a[i]) {
            return static_cast<T>(i);
        }
    }
}

And would be used as follows:

enum StateType {START, STOP};
const int MAXVALUES = STOP+1;
const string stateNames[MAXVALUES] = {"START", "STOP"};

enum StateType state;

ifstream ifile;
ifile.open("input.txt");

ifile >> foo;
state = a2e <enum StateType> (foo, stateNames, MAXVALUES);

Hope this helps someone in the future. Thanks to everyone who made suggestions about how to tackle this problem.




回答5:


I think this would be an improvement on blcArmadillo's template answer and navigator's output answer. In file AToE.h:

#ifndef AToE_h
#define AToE_h

#include <string>
#include <stdexcept>
#include <cctype>

template <class T, char* A, int size, char* enumName> class AToE
{
  std::string S[size]; // to hold A as std::string
  T t;
  bool valid; // whether t holds a valid value

public:
  AToE()
  {
    initialize();
    valid = false;
  };

  AToE(T& t) : t(t)
  {
    initialize();
    valid = true;
  };

  AToE(std::string const& s)
  {
    initialize();
    valid = true;
    t = toEnum(s); // this has to be done after initialize()
  };

  void initialize()
  {
    int i = 0, j = 0;
    while (i < size)
    {
      while (A[j] != ',')
      {
        if (not isspace(A[j]))
        {
          S[i] += A[j];
        }
        ++j;
      }
      ++j; // to count skipped comma
      ++i;
    }
  };

  T get()
  {
    if (valid) return t;

    std::string e = "ERROR - IO object is not initialized to a valid ";
    e += enumName;
    throw std::runtime_error(e);
  };

  friend std::ostream& operator<<(std::ostream& os, AToE& a)
  {
    if (a.valid) return os << a.S[a.t];

    std::string e = "OUTPUT ERROR - IO object is not initialized to a valid ";
    e += enumName;
    throw std::runtime_error(e);
  };

  T toEnum(std::string const& s)
  {
    for (int i=0; i<size; ++i)
    {
      if (s == S[i])
      {
        valid = true;
        t = static_cast<T>(i);
        return t;
      }
    }

    std::string e = "CONVERSION ERROR - " + s + " is not a valid " + enumName;
    throw std::out_of_range(e);
  }

  std::string toString();
  {
    if (valid) return S[t];

    std::string e = "CONVERSION ERROR - IO object is not initialized to a valid ";
    e += enumName;
    throw std::runtime_error(e);
  }

  friend std::istream& operator>>(std::istream& is, AToE& a)
  {
    std::istream::sentry isSentry(is); // sentry for is
    if (not isSentry) return is; // stream error

    std::string s;
    if (is >> s) a.t = a.toEnum(s);

    return is;
  }
};
#endif

which can then be used like this in StateType.h:

#ifndef StateType_h
#define StateType_h
#include "AToE.h"

enum StateType {START, STOP, NUMBER_OF_STATE_TYPES};
char STATE_TYPE_NAMES[] = "START, STOP,"; // last comma is necessary
char STATE_TYPE_NAME = "StateType";
typedef AToE <StateType, STATE_TYPE_NAMES, NUMBER_OF_STATE_TYPES, STATE_TYPE_NAME> StateTypeIO_T;
#endif

and in the main:

#include <cstdio>
#include <fstream>
#include <iostream>
#include "StateType.h"

int main()
{
  std::ifstream infile;
  infile.open("input.txt");

  StateTypeIO_T stateIO; // uses AToE() constructor
  //StateType t = stateIO.get(); // uncomment to test get fail condition
  //std::cout << stateIO<< std::endl; // uncomment to test << fail condition
  while (infile >> stateIO) // uses AToE >> operator
  {
    std::cout << stateIO<< std::endl; // uses AToE << operator
    StateType s = stateIO.get(); // uses AToE get method
    StateTypeIO_T stateOut(s); // uses AToE(T& t) constructor
    std::cout << stateOut << endl;
  }

  // remove DOG from input.txt in order for the program to run past here

  std::string stateString = "STOP";
  std::cout << stateString << std::endl; // prints STOP
  StateTypeIO_T stateIO2(stateString); // uses AToE(std::string const& s) constructor
  std::cout << stateIO2 << std::endl; // prints STOP
  printf("state = %s\n", stateIO2.toString().c_str()); // prints state = STOP
  stateString = "START";
  stateIO2.toEnum(stateString); // sets stateIO2.t to START
  std::cout << stateIO2 << std::endl; // prints START

  StateTypeIO_T stateIO3();
  //std::cout << stateIO3.toString() << std::endl; // uncomment to test toString fail condition

  StateType s2;
  //s2 = stateIO3.toEnum("CAT"); // uncomment to test toEnum fail condition
  s2 = stateIO3.toEnum("STOP");
  std::cout << stateIO3 << std::endl; // prints STOP
  StateTypeIO_T stateOut2(s2);
  std::cout << stateOut2 << std::endl; // prints STOP
};

which can be used with an input.txt file -

START
STOP
STOP
START
DOG

which will print out each entry twice until it hits the INPUT ERROR on DOG, and if you remove DOG from input.txt, it will print out each entry twice followed by -

STOP
STOP
state = STOP
START
STOP
STOP



回答6:


@popester

I'd post this as a response but from past experience code doesn't translate too well in post replies on SO.

I just wrote up the following short program to test what you suggested:

#include <iostream>
#include <fstream>

using namespace std;

int main() {
    enum Type {
        START,
        STOP
    };

    int bar;
    enum Type foo;

    ifstream ifile;
    ifile.open("input.txt");

    ifile >> bar;

    foo = (Type) bar;
    cout << "bar: " << bar << endl;

    cout << "foo: " << foo << endl;
}

Below is my input.txt file:

STOP

I compiled and ran the program and it output the following:

bar: -1207974988
foo: -1207974988

Am I just misunderstanding what you're suggesting? If you could lead me in the right direction that would be great. Thanks for your help.



来源:https://stackoverflow.com/questions/1619732/how-to-assign-a-value-to-an-enum-based-on-input-from-a-file-in-c

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!