简体   繁体   中英

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

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?

最快的方法是读入一个int并将其强制转换为Type枚举。

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 .

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

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.

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

@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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM