Я думаю, что это улучшит шаблонный ответ blcArmadillo и выходной ответ навигатора. В файле 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
, который затем можно использовать в 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
и в основном:
#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
};
, который можно использовать с файлом input.txt -
START
STOP
STOP
START
DOG
, которая будет печатать каждую запись дважды, пока не достигнет ОШИБКИ ВВОДА в DOG, и если вы удалите DOG из input.txt, она напечатает каждую запись дважды, после чего -
STOP
STOP
state = STOP
START
STOP
STOP