Как назначить значение для перечисления на основе ввода из файла в C ++? - PullRequest
2 голосов
/ 25 октября 2009

У меня есть файл со значениями, такими как: START и STOP. У меня также объявлено следующее перечисление:

enum Type {
    START,
    STOP
};

Я пытаюсь установить enum равным первому значению в файле примерно так:

enum Type foo;

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

ifile >> foo;

Я получаю сообщение об ошибке: нет совпадения с оператором >> в ifile >> foo.

Как мне сделать это правильно?

Ответы [ 6 ]

5 голосов
/ 25 октября 2009

Самое быстрое, что нужно сделать, это прочитать int и привести его к типу enum.

1 голос
/ 29 января 2019

Я думаю, что это улучшит шаблонный ответ 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
1 голос
/ 27 октября 2009

Для моей конкретной ситуации я обнаружил, что следующий код является лучшим решением:

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

И будет использоваться следующим образом:

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

Надеюсь, это поможет кому-то в будущем. Спасибо всем, кто высказал предложения о том, как решить эту проблему.

1 голос
/ 25 октября 2009

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;
}
1 голос
/ 25 октября 2009

Оператор вставки потока не перегружен для пользовательских типов. Вы можете либо определить один для вашего enum объекта типа Type, либо использовать одну из существующих перегрузок для чтения unsigned char или bool, а затем изменить значение на enum.

0 голосов
/ 25 октября 2009

@ popester

Я бы опубликовал это как ответ, но из прошлого опыта код не очень хорошо переводится в пост-ответах на SO.

Я только что написал следующую короткую программу, чтобы проверить, что вы предложили:

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

Ниже мой файл input.txt:

СТОП

Я скомпилировал и запустил программу, и она выдала следующее:

бар: -1207974988
foo: -1207974988

Я просто неправильно понимаю, что вы предлагаете? Если бы вы могли привести меня в правильном направлении, это было бы здорово. Спасибо за вашу помощь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...