1

私が持っているいくつかのサンプルコーディングに問題があります。理想的には、変更可能なデータ (int と文字列) が関連付けられたキーワードを持つファイルが必要です。いつでも編集できる期間 (int)、宛先 (文字列)、およびソース (ソース) があります。これは、最終的には、ファイルがどこにあり、どこに行くのか、設定された日数のファイルをバックアップする使いやすさのためです。

これは私が持っているサンプル コードです。いくつかのエラーを修正しましたが、最後の 2 つのエラーで立ち往生しています。または、これを行うためのより簡単な方法はありますか? ごちゃごちゃしてすみません、私はかなり新しいC ++です...

助けてくれてありがとう、私はそれを経験することがたくさんあることを知っています。たぶん、誰かが簡単な構成ファイルの解析に関する優れたチュートリアルを持っているので、私も読むことができますか?

私のgccバージョンは4.4.7です

私が受け取っているエラーは次のとおりです。

g++ configFile.cpp configFile.cpp:36: エラー: 名前空間以外のスコープでの明示的な特殊化 'class Convert' configFile.cpp: 静的メンバー関数内 'static T Convert::string_to_T(const std::string&)': configFile.cpp :31: エラー: テンプレート パラメータに依存する 'exitWithError' への引数がないため、'exitWithError' の宣言が利用可能である必要があります configFile.cpp:31: 注: ('-fpermissive' を使用すると、G++ は受け入れますただし、宣言されていない名前の使用を許可することは非推奨です)

#include <iostream>
#include <string>
#include <sstream>
#include <map>
#include <fstream>
#include <vector>
#include <stdio.h>
#include <stdlib.h>

using namespace std;

class Convert
{

public:
template <typename T>
static std::string T_to_string(T const &val) 
{
    std::ostringstream ostr;
    ostr << val;

    return ostr.str();
}

template <typename T>
static T string_to_T(std::string const &val) 
{
    std::istringstream istr(val);
    T returnVal;

    if (!(istr >> returnVal))
        exitWithError("CFG: Not a valid " + (std::string)typeid(T).name() + " received!\n");

    return returnVal;
}

template <>
static std::string string_to_T(std::string const &val)
{

    return val;
}
};

void exitWithError(const std::string &error) 
{
std::cout << error;
std::cin.ignore();
std::cin.get();

exit(EXIT_FAILURE);
}

class ConfigFile
{

private:
std::map<std::string, std::string> contents;
std::string fName;

void removeComment(std::string &line) const
{
    if (line.find(';') != line.npos)
        line.erase(line.find(';'));
}

bool onlyWhitespace(const std::string &line) const
{
    return (line.find_first_not_of(' ') == line.npos);
}

bool validLine(const std::string &line) const
{
    std::string temp = line;
    temp.erase(0, temp.find_first_not_of("\t "));

    if (temp[0] == '=')

        return false;

    for (size_t i = temp.find('=') + 1; i < temp.length(); i++)

                    if (temp[i] != ' ')

            return true;

    return false;
}

void extractKey(std::string &key, size_t const &sepPos, const std::string &line) const
{
    key = line.substr(0, sepPos);
    if (key.find('\t') != line.npos || key.find(' ') != line.npos)
        key.erase(key.find_first_of("\t "));
}
void extractValue(std::string &value, size_t const &sepPos, const std::string &line) const
{
    value = line.substr(sepPos + 1);
    value.erase(0, value.find_first_not_of("\t "));
    value.erase(value.find_last_not_of("\t ") + 1);
}
void extractContents(const std::string &line) 
{
    std::string temp = line;
    temp.erase(0, temp.find_first_not_of("\t "));
    size_t sepPos = temp.find('=');
    std::string key, value;
    extractKey(key, sepPos, temp);
    extractValue(value, sepPos, temp);

    if (!keyExists(key))
        contents.insert(std::pair<std::string, std::string>(key, value));
    else
        exitWithError("CFG: Can only have unique key names!\n");
}
void parseLine(const std::string &line, size_t const lineNo)
{
    if (line.find('=') == line.npos)
        exitWithError("CFG: Couldn't find separator on line: " + Convert::T_to_string(lineNo) + "\n");

    if (!validLine(line))
        exitWithError("CFG: Bad format for line: " + Convert::T_to_string(lineNo) + "\n");

    extractContents(line);
}
void ExtractKeys()
{
    std::ifstream file;
    file.open(fName.c_str());
    if (!file)
        exitWithError("CFG: File " + fName + " couldn't be found!\n");

    std::string line;
    size_t lineNo = 0;
    while (std::getline(file, line))
    {

        lineNo++;
        std::string temp = line;
        if (temp.empty())
            continue;

        removeComment(temp);
        if (onlyWhitespace(temp))
            continue;

        parseLine(temp, lineNo);
    }
    file.close();
}
public:
ConfigFile(const std::string &fName)
{
    this->fName = fName;
    ExtractKeys();
}
bool keyExists(const std::string &key) const
{
    return contents.find(key) != contents.end();
}
template <typename ValueType>

ValueType getValueOfKey(const std::string &key, ValueType const &defaultValue = ValueType()) const
{
    if (!keyExists(key))
        return defaultValue;

    return Convert::string_to_T<ValueType>(contents.find(key)->second);
}
};

int main()
{

ConfigFile cfg("config.cfg");



bool exists = cfg.keyExists("car");

std::cout << "car key: " << std::boolalpha << exists << "\n";

exists = cfg.keyExists("fruits");

std::cout << "fruits key: " << exists << "\n";



std::string someValue = cfg.getValueOfKey<std::string>("mykey", "Unknown");

std::cout << "value of key mykey: " << someValue << "\n";

std::string carValue = cfg.getValueOfKey<std::string>("car");

std::cout << "value of key car: " << carValue << "\n";

double doubleVal = cfg.getValueOfKey<double>("double");

std::cout << "value of key double: " << doubleVal << "\n\n";



std::cin.get();

return 0;

}
4

1 に答える 1

0

次のコードで、それを特殊化しようとしましたか?

template <>
static std::string string_to_T(std::string const &val)
{

    return val;
}

その場合、エラーが示すように、クラスの外部で明示的な特殊化を定義する必要があります ( explicit specialization in non-namespace scope):

template <>
std::string Convert::string_to_T<std::string>(std::string const &val)
{

    return val;
}

また、でexitWithError使用する前に、Convertまたは前方宣言する必要があります。これは、で使用するときにコンパイラがまだ認識していないためですConvert。の定義の前に移動しますConvert:

void exitWithError(const std::string &error) 
{
std::cout << error;
std::cin.ignore();
std::cin.get();

exit(EXIT_FAILURE);
}
// Or just forward declare void exitWithError(const std::string &);

class Convert
{ ....
于 2013-08-01T21:13:41.000 に答える