自动,模板?如何构造返回不同数据类型的方法

时间:2018-06-09 15:20:26

标签: c++ templates auto

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

如果有人也可以举例说明如何正确转换我的搜索方法的模板方法。 谢谢你的回应,我没有想法......

2 个答案:

答案 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 >>重载的所有类型,其中包括基本类型,例如floatint。此外,您可以为自定义类型重载运算符。

有了这个,您可以实现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);