1

I am having some problems with some sample coding I have. Ideally I want a file that will have key words, that have data (int and strings) associated with them that can be changed. I will have duration (int), destination(string), and source(source) that can be edited at any time. This will be ultimately for ease of use backing up files for a set time in days, where they are and where they are going.

This is the sample code I have, I have fixed quit a few errors but am stuck on the last couple. Or is there an easier way about doing this? Sorry its all jumbled, I am pretty new C++...

Thank you for the help, I know its a lot to go through. Maybe someone has a good tutorial on easy configuration file parsing I could read up on also?

My gcc version is 4.4.7

The errors I am recieving are:

g++ configFile.cpp configFile.cpp:36: error: explicit specialization in non-namespace scope ‘class Convert’ configFile.cpp: In static member function ‘static T Convert::string_to_T(const std::string&)’: configFile.cpp:31: error: there are no arguments to ‘exitWithError’ that depend on a template parameter, so a declaration of ‘exitWithError’ must be available configFile.cpp:31: note: (if you use ‘-fpermissive’, G++ will accept your code, but allowing the use of an undeclared name is deprecated)

#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;

}
user2630969
  • 57
  • 1
  • 6

1 Answers1

0

With the following code, were you trying to specialize it?

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

    return val;
}

If that is the case, explicit specialization need to be defined outside of the class as the error says (explicit specialization in non-namespace scope):

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

    return val;
}

Also, you need exitWithError before you use it in Convert or forward declare it since the compiler has not seen it yet when you use it in Convert. Move it before the definition of 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
{ ....
Jesse Good
  • 50,901
  • 14
  • 124
  • 166
  • Thank you for catching my placement error with "exitWithError". For the specialized error, I don't have to have it specialized. Fom my research it seemed like a good way to accomplish what i am going for. Do you recommend any other options? I am still getting any error for explicit specialization, but will report when I can figure out my mistake. Thank you Jesse. – user2630969 Aug 02 '13 at 13:58
  • @user2630969: Specialization looked like the way to go. [Here is an example of your code that compiled for me](http://coliru.stacked-crooked.com/view?id=6a4810be9bc5b661781797df409dfc02-f674c1a6d04c632b71a62362c0ccfc51). – Jesse Good Aug 02 '13 at 21:13
  • Thank you Jesse, this is exactly what I am was trying to do. Sending some good vibes your way! – user2630969 Aug 06 '13 at 19:48