汽车,模板?如何构造返回不同数据类型的方法
auto, template? How to construct method returning different datatypes
[信息]
我是新来的,而且...是编程新手。我学习 C(几乎没有 C++)大约一年了,现在我被困住了。我目前正在编写我的第一个更大的应用程序用于培训目的,并且作为每个程序员 - 我正在尝试尽可能地懒惰。我的应用程序基于用于绘制图形的简单快速多媒体库 (SFML),当然还有用于逻辑的 C/C++。我厌倦了在代码中隐藏许多不同的变量(比如 Window 分辨率,Window 位置等)所以我开始编写 class 来读取带有配置的 *txt 文件(你知道: config.ini 类似 "iWindowResolutionX=1920;")。打开 *txt 文件、解释它们并提取所需数据的算法正在运行(可能它非常糟糕 - 但是嘿,它正在运行 :P)
[问题]
我坚持非常基本的事情。
我有我的配置文件 reader class 的对象,我想实现这样的目标:
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.
我卡在这里了。如何强制方法 return 不同的基本数据类型(char、int、float 等)?
}
我试过将方法 return 类型定义为 "auto",但它给了我一个错误 "a function that returns 'auto' cannot be used before it is defined"(我不明白 VS 在这里跟我说什么)和然后关于尝试 return 不同于第一次选择的数据类型的错误(这很简单,如果编译器第一次看到 "return value",它不允许我 return 任何其他数据类型)。
我接下来尝试的是模板方法,但我太笨了,无法理解它 ;)
好的,有一个简单的解决方案 - 我可以针对我想要的 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] != '[=12=]';
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
任何人都可以指出如何转换搜索方法以便能够 return 不同的数据类型:
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;
}
如果有人也可以给我一个例子,说明如何正确地将我的搜索方法转换为模板方法。
感谢您的回复,我没有想法...
使用模板执行此操作的一种方法是使用 "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);
}
I've tried defining method return type as "auto", but it gives me an error "a function that returns 'auto' cannot be used before it is defined" (I don't understand what's VS is talking to me here)
就个人而言,我不太经常使用 VS,但我想这意味着编译器在调用方法时必须看到方法的主体(定义)。这是必要的——毕竟,当使用 auto
(没有尾随 return 类型)时,编译器必须根据函数体推断出 returned 类型。
我建议为每种数据类型实现单独的方法。
你知道目标变量的数据类型,对吧?然后你可以做一些这样的方法:
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);
[信息]
我是新来的,而且...是编程新手。我学习 C(几乎没有 C++)大约一年了,现在我被困住了。我目前正在编写我的第一个更大的应用程序用于培训目的,并且作为每个程序员 - 我正在尝试尽可能地懒惰。我的应用程序基于用于绘制图形的简单快速多媒体库 (SFML),当然还有用于逻辑的 C/C++。我厌倦了在代码中隐藏许多不同的变量(比如 Window 分辨率,Window 位置等)所以我开始编写 class 来读取带有配置的 *txt 文件(你知道: config.ini 类似 "iWindowResolutionX=1920;")。打开 *txt 文件、解释它们并提取所需数据的算法正在运行(可能它非常糟糕 - 但是嘿,它正在运行 :P)
[问题] 我坚持非常基本的事情。 我有我的配置文件 reader class 的对象,我想实现这样的目标:
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.
我卡在这里了。如何强制方法 return 不同的基本数据类型(char、int、float 等)? }
我试过将方法 return 类型定义为 "auto",但它给了我一个错误 "a function that returns 'auto' cannot be used before it is defined"(我不明白 VS 在这里跟我说什么)和然后关于尝试 return 不同于第一次选择的数据类型的错误(这很简单,如果编译器第一次看到 "return value",它不允许我 return 任何其他数据类型)。
我接下来尝试的是模板方法,但我太笨了,无法理解它 ;)
好的,有一个简单的解决方案 - 我可以针对我想要的 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] != '[=12=]';
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
任何人都可以指出如何转换搜索方法以便能够 return 不同的数据类型:
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;
}
如果有人也可以给我一个例子,说明如何正确地将我的搜索方法转换为模板方法。 感谢您的回复,我没有想法...
使用模板执行此操作的一种方法是使用 "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);
}
I've tried defining method return type as "auto", but it gives me an error "a function that returns 'auto' cannot be used before it is defined" (I don't understand what's VS is talking to me here)
就个人而言,我不太经常使用 VS,但我想这意味着编译器在调用方法时必须看到方法的主体(定义)。这是必要的——毕竟,当使用 auto
(没有尾随 return 类型)时,编译器必须根据函数体推断出 returned 类型。
我建议为每种数据类型实现单独的方法。 你知道目标变量的数据类型,对吧?然后你可以做一些这样的方法:
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);