2014-10-05 21 views
0

使用C++,我很好奇我该如何去读取一个文件中的值,这个文件必须进入枚举类型。如何将文件中的值直接读入C++中的枚举类型?

例如,我的文件格式是这样的:

firstname lastname strength weapon 

如果我把它改写为数据类型,它是

string string int enum 

现在我意识到我使用

ifstream din; 
din >> strVal; 
//that's for strings, for ints I use: 
din >> intVal; 

如何从文件中读取必须进入枚举类型的值?我知道他们必须事先被定义,我做到了。但是我不能将strVal转换为枚举类型,所以我不知道如何去做。

预先感谢您向大家试图帮助:)

+0

请参阅:[如何将枚举类型变量转换为字符串?](http://stackoverflow.com/questions/5093460/how-to-convert-an-enum-type-variable-to-a-string ) - 你也可以走相反的路。 – Vector 2014-10-05 23:40:59

+0

@Vector我不知道这是可能的另一种方式,我绝对会读这个吧!谢谢! – SiggyxLeGiiT 2014-10-05 23:43:12

+0

当你说你的文件格式的武器,我假设你的意思是相当于整数,而不是作为一个字符串的枚举名称,对不对? – Kevin 2014-10-06 02:43:32

回答

0

首先你需要(文件)枚举值(该计划)和字符串之间的映射。它可能只是以十进制表示的整数值。或者例如枚举成员名称。

名称具有可读性好的优点,尤其是当它们是英文的时候,但缺点是它们需要一些额外的机器以及开发和维护工作。定义名称字符串

的一种方法是简单地使用名字的阵列,以及用于些许的完整性检查检查该数组的大小等于枚举值的数目:

#include <iostream> 
#include <stdexcept>  // std::exception, std::runtime_error 
#include <stdlib.h>   // EXIT_FAILURE, EXIT_SUCCESS 
#include <string> 

namespace my { 
    using std::ios; 
    using std::istream; 
    using std::string; 

    struct Weekday 
    { 
     enum Enum{ monday, tuesday, wednesday, thursday, friday, saturday, sunday }; 
     static Enum constexpr first_value = monday; 
     static Enum constexpr last_value = sunday; 
     static int constexpr n_values  = last_value + 1; 

     static 
     auto identifiers() -> char const* const (&)[n_values] 
     { 
      static char const* const the_identifiers[] = 
      { "monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday" }; 
      return the_identifiers; 
     } 
    }; 

可替代地,预处理器或通用代码生成可用于生成相应的枚举值名称和名称字符串,但恕我直言,这是更值得的工作。

使用可用的名称,您只需要支持>>即可定义合适的operator>>,例如,如下:

istream& operator>>(istream& stream, Weekday::Enum& value) 
    { 
     string name; 
     if(stream >> name) 
     { 
      for(int i = 0; i < Weekday::n_values; ++i) 
      { 
       if(name == Weekday::identifiers()[i]) 
       { 
        value = Weekday::Enum(i); 
        return stream; 
       } 
      } 
      stream.setstate(ios::failbit); 
     } 
     return stream; 
    } 
} // namespace my 

这里我选择使用相同的故障报告与标准的输入操作,通过流状态即。或者可以使用例外。然而,正如我所看到的,例外属于更高层次,例如在调用代码中:

using namespace std; 

void cpp_main() 
{ 
    my::Weekday::Enum day; 
    cout << "Day? "; 
    cin >> day; 
    if(!cin) { throw runtime_error("Not a valid weekday name."); } 
    cout << "You chose a " << my::Weekday::identifiers()[day] << "." << endl; 
} 

auto main() -> int 
{ 
    try 
    { 
     cpp_main(); return EXIT_SUCCESS; 
    } 
    catch(exception const& x) 
    { 
     cerr << "!" << x.what() << endl; 
    } 
    return EXIT_FAILURE; 
} 

就是这样,除了优化。字符串查找可以通过将字符串放在std::mapstd::unordered_map中进行优化。但是对于流I/O来说,主要的时间消费者是I/O,所以对查找的任何优化都可能不会产生任何显着的整体性能改进。


注:用Visual C++ 12.0编译这个,不支持constexpr,使用/D constexpr=const /D _ALLOW_KEYWORD_MACROS

+0

我有兴趣阅读当你回来时说什么!我的枚举确实是字符串,而不是整数,只是说。 :) – SiggyxLeGiiT 2014-10-05 23:53:58

0

解决此问题的一种方法是使用这样一个事实,即枚举映射中的值自动分配为从0开始的整数值。您可以使用任何您想要的数字初始化您的值,然后为您的逻辑检查创建数字代码。

考虑下面的枚举映射:

enum Weapon {KNIFE = 1, CHAINSAW = 2, HANDGUN = 3, ASSULT_RIFLE = 3, ROCKET_LAUNCHER = 4, ... }; 

您从文件中获取您的输入值后,您就可以在的if-else和开关条件使用这些分配的整数值。从这里开始,使用一个简单的开关将正确的值赋给枚举变量很容易。

你可以尝试这样的事情:

int startingWeapon; 
Weapon currentWeapon; 
din >> strValue >> str2Value >> intValue >> startingWeapon; 
switch (startingWeapon) 
{ 
    case 1: 
     currentWeapon = KNIFE; 
     cout << "Weapon: Knife.\n"; 
     break; 
    case 2: 
     currentWeapon = CHAINSAW; 
     cout << "Weapon: Chainsaw.\n"; 
     break; 
. 
. 
. 
    default: 
     currentWeapon = KNIFE; 
     cout << "Weapon: Knife.\n"; 
} 

这就是说,它不可能用整数值来初始化枚举类型的变量。这将导致一个编译器错误:

Weapon currentWeapon = 1; 

这是正确的做法:

Weapon currentWeapon = KNIFE; 
+0

请注意,在C++ 11中,您应该更喜欢enum类来确保其类型安全。但是,IIRC,这意味着你必须自己编写运算符<<和运算符>>,但这是相当简单的。 – Kevin 2014-10-06 02:45:13

0

你将不得不从一个字符串或一个int您枚举类型转换。封装这个的一种方法是通过重载operator<<()。您可能还想要输出operator>>()