Click here to Skip to main content
15,881,709 members
Please Sign up or sign in to vote.
1.00/5 (2 votes)
See more: , +
I am try in to create a parser with to read configuration files
error explicit specialisation in non namespace 'class Conversion'

What I have tried:

C++
#include <iostream>
#include <string>
#include <sstream>
#include <map> //holding the pair of parameter-value
#include <fstream>
#include <stdlib.h>
#include <typeinfo>


void FileNotFound(const std::string &error)
{
	std::cout << error;
	std::cin.get();
	exit(EXIT_FAILURE);
}


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

		return ostr.str();
	}

	template <typename T>
	static T stringtoT(std::string const &val)
	{
		std::istringstream istr(val);
		T returnVal;
		if (!(istr >> returnVal))
			FileNotFound("Not a valid " + (std::string)typeid(T).name() + " present\n");

		return returnVal;
	}

	template <>
	static std::string stringtoT(std::string const &val)
	{
		return val;
	}
};


class Parser
{
    private:
	std::map<std::string, std::string> contents;
	std::string filename;

//function itself is a const cannot call any non-const member functions, nor can it change any member variables.
    void Deletecomments(std::string &line) const
	{  //npos is a static member constant value with the greatest possible value for an element of type size_t

		if (line.find(';') != line.npos)
		line.erase(line.find(';'));

	}
//Searches the string for the first character that does not match any of the characters specified in its arguments.
    bool Whitespace(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 Key(std::string &key, size_t const &Pos, const std::string &line) const
	{
		key = line.substr(0, Pos);
		if (key.find('\t') != line.npos || key.find(' ') != line.npos)
			key.erase(key.find_first_of("\t "));
	}
	void Value(std::string &value, size_t const &Pos, const std::string &line) const
	{
		value = line.substr(Pos + 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 Pos = temp.find('=');

		std::string key, value;
		Key(key, Pos, temp);
		Value(value, Pos, temp);

		if (!keyExists(key))
			contents.insert(std::pair<std::string, std::string>(key, value));
		else
			FileNotFound("Can only have unique key names!\n");
	}

    void parse(const std::string &line, size_t const lineNumber)
	{
		if (line.find('=') == line.npos)
			FileNotFound("Cannot find separator " + Conversion::Ttostring(lineNumber) + "\n");

		if (!validLine(line))
			FileNotFound("Bad format for line: " + Conversion::Ttostring(lineNumber) + "\n");

		extractContents(line);
	}
    /*
	  Extracting the parameter and values
	*/
	void getfield()
	{
		std::ifstream file;
		file.open(filename.c_str()); //c_str() return the char*
		if (!file)
			FileNotFound("" + filename + " not found!\n");

		std::string line;
		size_t lineNumber = 0; //unsigned integer type
		while (std::getline(file, line))
		{
			lineNumber++;
			std::string temp = line;

			if (temp.empty())
				continue;

			Deletecomments(temp);
			if (Whitespace(temp))
				continue;

			parse(temp, lineNumber);
		}

		file.close();
	}

   public:
	Parser(const std::string &filename)
	{
		this->filename = filename;
		getfield();
	}


	bool keyExists(const std::string &key) const
	{
		return contents.find(key) != contents.end();
	}

	/*function that retrieves the value of a specific key
	 function returns a default value ValueType, if the key couldn't be found or,
	 it will return the Conversion value from string to ValueType
	*/
	template <typename ValueType>
	ValueType getValueOfKey(const std::string &key, ValueType const &defaultValue = ValueType()) const
	{
		if (!keyExists(key))
			return defaultValue;

		return Conversion::stringtoT<ValueType>(contents.find(key)->second);
	}
};

int main()
{
	Parser Par("ParameterFile");

	bool exists = Par.keyExists("Parameter1");
	std::cout << "Parameter1 key: " << std::boolalpha << exists << "\n";
	exists = Par.keyExists("Value1");
	std::cout << "Value1 key: " << exists << "\n";

	std::cin.get();
	return 0;
}
Posted
Updated 22-Mar-17 11:51am
v2
Comments
PIEBALDconsult 19-Mar-17 17:54pm    
It might be helpful to others is you stated what compiler you're using and the _full_ text of the error message.
FarhanShariff 19-Mar-17 18:03pm    
I am using code blocks 13.2

1 solution

Here are three choices for you:

Easiest fix is to get rid of the Conversion class and write specialized versions of getValueOfKey.

Alternative 2: make Conversion a template class (instead of a class with template members).
C++
template <typename T> class Conversion {

Alternative 3: make Conversion a namespace.
C++
<pre>namespace Conversion {

Additional comments:

Value, Key, Whitespace, deleteComments, and validLine can be static instead of const member functions.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900