[INFO]
我是新来的......对编程很新。我正在学习C(用很少的C ++)大约一年,现在我被卡住了。我正在编写我的第一个更大的应用程序用于培训目的和每个程序员 - 我试图尽可能地懒惰。我的应用程序基于简单快速多媒体库(SFML),用于绘制图形,当然还有C / C ++用于逻辑。我厌倦了在代码中隐藏了许多不同的变量(比如Window Resolution,Window Position等),所以我开始编写用于读取带有配置的* txt文件的类(你知道:config.ini有类似“iWindowResolutionX = 1920;”的东西) )。打开* txt文件,解释它们并提取所需数据的Algorythm正在工作(可能它非常糟糕 - 但是嘿,它正在工作:P)
[问题] 我坚持非常基本的事情。 我有我的配置文件阅读器类的对象,我想实现这样的事情:
Int main()
{
int WindowResolutionX = 0; //nothing special - int with value of 0.
CfgReader cfg_object("config.ini"); // object of CfgReader class with custom
constructor passing name of *txt
configuration file.
WindowResolutionX = cfg_object.Search("iWindowResolutionX"); // As you see - I want to write a code that calls method "Search" on cfg_object. This method takes variable name as parameter and after sucsess (value found) returns it.
在这里,我被困住了。如何强制方法返回不同的基本数据类型(char,int,float等)? }
我已经尝试将方法返回类型定义为“auto”,但它给了我一个错误“返回'auto'的函数在定义之前无法使用”(我不明白VS在跟我说话是什么在这里)然后错误尝试返回不同于首先选择的数据类型(这很简单,如果编译器第一次看到“返回值”,它不能允许我返回任何其他数据类型)。
接下来我尝试过的是模板方法,但我要愚蠢地理解它;)
好的,有一个简单的解决方案 - 我可以将我的搜索方法复制X次以获得我想要的X数据类型,只是简单地重载它 - 但这不是优雅的解决方案,也不会教我任何新东西。在我的代码下面:
“CfgReader.h”
#pragma once
#include "fstream"
#include <iostream>
#include <string>
class CfgReader
{
public:
FILE *fp;
const char * cfg_filename;
size_t filesize;
std::string line;
int int_val;
float float_val;
char char_val;
bool bool_val;
long long_val;
std::string string_val;
size_t size_t_val;
public:
void OpenFile(const char * filename);
void CloseFile();
auto Search(const char * search_val);
void Show_content();
int r_int();
char r_char();
float r_float();
size_t r_size_t();
long r_long();
bool r_bool();
std::string r_string();
CfgReader();
CfgReader(const char *);
~CfgReader();
};
“CfgReader.cpp”
#include "CfgReader.h"
#pragma warning(disable: 4996)
CfgReader::CfgReader()
{
CfgReader("");
}
CfgReader::CfgReader(const char * filename)
{
if ((sizeof(filename) == 1) && (filename[0] == 0))
{
std::cout << "\n CfgReader No filename.";
cfg_filename = "";
fp = NULL;
}
else
{
std::cout << "\n test";
line = "";
int_val = NULL;
float_val = NULL;
char_val = NULL;
bool_val = false;
long_val = NULL;
string_val = "";
size_t_val = NULL;
cfg_filename = filename;
OpenFile(cfg_filename);
}
}
void CfgReader::OpenFile(const char * filename)
{
fp = fopen(filename, "rb");
if (fp != NULL)
{
std::cout << "\n good!";
}
else
{
std::cout << "\n Error, could not open file.";
}
rewind(fp);
fseek(fp, 0, SEEK_END);
filesize = ftell(fp);
rewind(fp);
std::cout << "\n filesize: " << filesize;
//system("pause");
}
void CfgReader::Search(const char * search_val)
{
size_t search_val_length = 0;
for (search_val_length; search_val[search_val_length] != '\0';
search_val_length++);
std::string test;
if (fp == NULL)
{
std::cout << "\n Error, file not loaded!";
}
else
{
char first_letter = 0;
bool match = false;
size_t counter = 0;
rewind(fp);
while (match == false)
{
while (first_letter != 13)
{
fread(&first_letter, sizeof(char), 1, fp);
}
if (first_letter == 13)
{
fread(&first_letter, sizeof(char), 1, fp);
if (first_letter == 10)
{
do
{
fread(&first_letter, sizeof(char), 1, fp);
if (first_letter == search_val[counter])
{
test += first_letter;
counter++;
if(counter==search_val_length)
{
match = true;
break;
}
}
else
{
counter = 0;
test = "";
break;
}
} while (first_letter != 61);
if (test == search_val || match == true)
{
match = true;
break;
}
}
}
std::cout << "\n ftell(fp): " << ftell(fp);
if (ftell(fp) == filesize) break;
}
if (match == false)
{
std::cout << "\n ERROR, no such VALUE!";
}
else
{
std::cout << "\n test string = " << test;
//system("pause");
//Show_content();
///line = test;
///test = "";
while (first_letter != 13)
{
fread(&first_letter, sizeof(char), 1, fp);
if (first_letter == 61)continue;
test += first_letter;
}
std::cout << "\n test string VALUE (string):" << test << std::endl;
switch (line[0])
{
case 'i':
int_val = std::stoi(test);
std::cout << "\n int_val: " << int_val;
//return int_val;
//a = int_val;
break;
case 'f':
float_val = std::stof(test);
std::cout << "\n float_val: " << float_val;
//return float_val;
//a = float_val;
break;
case 'b':
if (test[0] == 'f' || test[0] == '0') bool_val = false;
else bool_val = true;
std::cout << "\n bool_val: " << bool_val;
//return bool_val;
//a = bool_val;
break;
case 'l':
long_val = std::stol(test);
std::cout << "\n long_val: " << long_val;
//return long_val;
//a = long_val;
break;
case 's':
string_val = test;
std::cout << "\n string_val: " << string_val;
//return string_val;
// a = string_val;
break;
case 't':
size_t_val = std::stoul(test);
std::cout << "\n size_t_val: " << size_t_val;
//return size_t_val;
//a = size_t_val;
break;
}
}
}
}
int CfgReader::r_int()
{
return int_val;
}
char CfgReader::r_char()
{
return char_val;
}
float CfgReader::r_float()
{
return float_val;
}
size_t CfgReader::r_size_t()
{
return size_t_val;
}
long CfgReader::r_long()
{
return long_val;
}
bool CfgReader::r_bool()
{
return bool_val;
}
std::string CfgReader::r_string()
{
return string_val;
}
void CfgReader::Show_content()
{
std::cout << "\n //--------------------------CfgReader.Show_content()------------------------\\"<<std::endl;
if (fp != NULL)
{
rewind(fp);
fseek(fp, 0, SEEK_END);
int filesize = ftell(fp);
char literka;
rewind(fp);
while (ftell(fp) != filesize)
{
fread(&literka, sizeof(char), 1, fp);
std::cout << "\n" << (short)literka << " - " << literka;
}
}
else
{
std::cout << "\n Error: fp == NULL.";
}
std::cout << "\n \\--------------------------/CfgReader.Show_content()------------------------// \n";
}
void CfgReader::CloseFile()
{
fclose(fp);
}
CfgReader::~CfgReader()
{
}
“Source.cpp”
#pragma warning(disable:4996)
#include "CfgReader.h"
int main()
{
CfgReader Config("config.ini");
Config.Search("iBitDepth");
system("pause");
return 0;
}
“的config.ini”
//------------------------ M_UPTIME config FILE ------------------------//
[Window]
iWindowResX=1920
iWindowResY=1080
fWindowScale=1
iWindowPosX=-1920
iWindowPosY=0
iBitDepth=32
[Screen Saver]
iScreenSaverTimeLimit=600
[TestValues]
bThisIsBool=false
bThisIsBoolToo=true
sThisIsString=Ala ma kota a kot ma ale
任何人都可以指出如何将Search方法转换为能够返回不同的数据类型:
int main()
{
int value_1 = 0;
CfgReader Config("config.ini");
value_1 = Config.Search("iBitDepth");
return 0;
}
或按此处工作:( CfgReader对象将变量引用作为参数)
int main()
{
int value_1 = 0;
CfgReader Config("config.ini");
Config.Search("iBitDepth", &value_1);
return 0;
}
如果有人也可以举例说明如何正确转换我的搜索方法的模板方法。 谢谢你的回应,我没有想法......
答案 0 :(得分:0)
使用模板执行此操作的一种方法是使用“lexical cast”(如Boost所称)。使用std::istringstream
实现简单的词法强制转换函数相对简单:
template<typename TargetType>
TargetType lexical_cast(const std::string& source)
{
TargetType result;
// create a stream for reading, initially containing source string
std::istringstream stream(source);
// read one value of type TargetType...
stream >> result;
// ...and return it
return result;
}
这适用于operator >>
重载的所有类型,其中包括基本类型,例如float
或int
。此外,您可以为自定义类型重载运算符。
有了这个,您可以实现Search
模板方法,将字符串转换为请求的类型:
template<typename TargetType>
TargetType Search(const std::string& key) const
{
std::string valueAsStr = // get it somehow, from a map, or file...
return lexical_cast<TargetType>(valueAsStr);
}
我已经尝试将方法返回类型定义为“auto”,但它给了我一个错误“返回'auto'的函数在定义之前无法使用”(我不明白VS在跟我说话是什么这里)
就个人而言,我不经常使用VS,但我想这意味着编译器在调用它时必须看到方法的主体(定义)。这是必要的 - 毕竟,当使用auto
(没有尾随返回类型)时,编译器必须根据函数体来推断返回的类型。
答案 1 :(得分:0)
我建议为每种数据类型实现单独的方法。 你知道目标变量的数据类型吗?然后你可以做几个像这样的方法:
int GetInt(const char* name, int defaultValue = 0) const;
std::string GetString(const char* name, const char* defaultValue = "") const;
并调用适当的方法:
int bitDepth = config.GetInt("Window.iBitDepth", 24);