How do I 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 declare the following enum:
enum Type {
START,
STOP
};
I am trying to set enum equal to the first value in a file with something like this:
enum Type foo;
ifstream ifile;
ifile.open("input.txt");
ifile >> foo;
I get the error: There is no match for 'operator β in' ifile β foo.
How can I make it right?
I found for my specific 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 it will be used like this:
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 on how to fix this issue.
The fastest thing to do is read into an int and cast it into your enum type.
The stream insert operator is not overloaded for user-defined types. You can define one for your object of enum
type, Type
or use one of the existing read unsigned char
or overloads bool
and then change the value to 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 think this will improve blcArmadillo template answer and navigator's output answer. In the AToE.h file:
#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 basically:
#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 the file input.txt -
START
STOP
STOP
START
DOG
which will print each record twice until it reaches the INPUT ERROR in DOG, and if you remove the DOG from input.txt it will print each record twice, after which -
STOP
STOP
state = STOP
START
STOP
STOP
@popester
I would post this as an answer, but from past experience code doesn't translate too well in SO answer posts.
I just wrote the following short program to check 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 the file input.txt:
STOP
I have compiled and run the program and it outputs the following:
bar: -1207974988
foo: -1207974988
I just don't understand what you are suggesting? If you could lead me in the right direction, that would be great. Thanks for your help.