I'm trying to use a Lua file as a config or an ini. I have succeeded but my solution irritates me. Specifically, get_double, get_int and get_string functions needs to be done in a reusable way.
I ran into problems creating function templates that don't have arguments.
Also, I'm not sure how to generalize lua_is... and lua_to.... My idea was to us if(is_same<T,double>::value) return (double)lua_isnumber(L,-1); but it didn't work.
Here is the working code:
main.cc:
#include <iostream>
#include <lua.hpp>
using namespace std;
class Lua_vm
{
private:
lua_State *L;
public:
double get_double(const char *var_name) {
lua_getglobal(L,var_name);
if (!lua_isnumber(L,-1)) {
cout << "error: " << var_name << " is of a wrong type\n";
}
return (double)lua_tonumber(L,-1);
lua_pop(L,1);
}
int get_int(const char *var_name) {
lua_getglobal(L,var_name);
if (!lua_isnumber(L,-1)) {
cout << "error: " << var_name << " is of a wrong type\n";
}
return (int)lua_tonumber(L,-1);
lua_pop(L,1);
}
string get_string(const char *var_name) {
lua_getglobal(L,var_name);
if (!lua_isstring(L,-1)) {
cout << "error: " << var_name << " is of a wrong type\n";
}
return string(lua_tostring(L,-1));
lua_pop(L,1);
}
Lua_vm(const char *lua_config_filename) {
L = lua_open();
if (luaL_loadfile(L, lua_config_filename) || lua_pcall(L, 0,0,0)) {
cout << "error: " << lua_tostring(L,-1) << "\n";
}
lua_pushnil(L);
}
~Lua_vm() {
lua_close(L);
}
};
int main(int argc, char** argv)
{
Lua_vm lvm("config.lua");
cout << "vol is " << lvm.get_double("vol") << "\n";
cout << "rho is " << lvm.get_int("rho") << "\n";
cout << "method is " << lvm.get_string("method") << "\n";
return 0;
}
config.lua:
method = "cube"
len = 3.21
rho = 13
vol = len*len*len
mass = vol*rho
It compiles with g++ main.C -I/usr/include/lua5.1/ -llua5.1 ; ./a.out
Here is code I use for that purpose (more: http://tom.rethaller.net/wiki/projects/prologue/lua)
class LuaState
{
private:
lua_State *L;
// [...]
public:
// get function
template<typename T>
T get(const char * varname) {
char temp[64];
memset(temp, 0, sizeof(temp));
int i=0;
int j=0;
int n=0;
while (varname[i] != '\0') {
char c = varname[i];
if (c == '.') {
if (n == 0)
lua_getglobal(L, temp);
else
lua_getfield(L, -1, temp);
++n;
memset(temp, 0, sizeof(temp));
j = 0;
if (lua_isnil(L, -1))
return 0;
}
else {
temp[j] = c;
++j;
}
++i;
}
if (n == 0)
lua_getglobal(L, temp);
else
lua_getfield(L, -1, temp);
return lua_get<T>();
}
// Generic get
template<typename T>
T lua_get() {
return 0;
}
// Specializations
template <> float lua_get<float>() {
return lua_tonumber(L, -1);
}
template <> double lua_get<double>() {
return lua_tonumber(L, -1);
}
template <> bool lua_get<bool>() {
return lua_toboolean(L, -1);
}
template <> int lua_get<int>() {
return lua_tointeger(L, -1);
}
template <> unsigned int lua_get<unsigned int>() {
return (unsigned int)lua_tonumber(L, -1);
}
template <> const char * lua_get<const char *>() {
return lua_tostring(L, -1);
}
};
-- Edit - To illustrate how to use it, you just have to call:
bool use_blur = lua_state.get<bool>("config.render.effects.blur");
to get the value of:
config = {
render = {
effects = {
blur = false,
}
}
}
Related
I am writing a program to implement queue using vectors. I am using the class as template. And in main function am trying to create both string vector and int vector based on template data type. However am getting compilation error from vector assign method.
template <class T>
class queueWithArray {
private:
vector<T> queueArray;
int numberOfElements;
int size;
int head;
int tail;
public:
queueWithArray(int n) {
numberOfElements = 0;
head = -1;
tail = -1;
size = n;
if(is_same<T,string>::value) {
cout << "data type is string" << endl;
queueArray.assign(n,"");
} else {
queueArray.assign(n,0);
}
}
...
int main() {
string InputArray[] = {"to", "be", "or", "not", "to", "-", "be", "-", "-", "that", "-", "-", "-", "is"};
queueWithArray<string> obj(2);
for(auto i=0; i < (signed int)(sizeof(InputArray)/sizeof(InputArray[0])); ++i) {
if(InputArray[i] == "-") {
string item = obj.dequeue();
cout << "dequeue->" << item << endl;
} else {
obj.enqueue(InputArray[i]);
cout << "enqueue->" << InputArray[i] << endl;
}
obj.printQueue();
}
int InputArray_int[] = {10,20,30,40,50,-1,20,-1,-1,60,-1,-1,-1,70};
queueWithArray<int> obj_int(2);
for(auto i=0; i < (signed int)(sizeof(InputArray_int)/sizeof(InputArray_int[0])); ++i) {
if(InputArray_int[i] == -1) {
int item = obj_int.dequeue();
cout << "dequeue->" << item << endl;
} else {
obj_int.enqueue(InputArray_int[i]);
cout << "enquque->" << InputArray_int[i] << endl;
}
obj.printQueue();
}
return 0;
}
..\QueueUsingTemplate.cpp:135:31: required from here
..\QueueUsingTemplate.cpp:45:4: error: no matching function for call to >'std::vector::assign(int&, const char [1])'
queueArray.assign(n,"");
^~~~~~~~~~
In file included from c:\mingw\lib\gcc\mingw32\6.3.0\include\c++\vector:64:0,
from c:\mingw\lib\gcc\mingw32\6.3.0\include\c++\queue:61,
from c:\mingw\lib\gcc\mingw32\6.3.0\include\c++\mingw32\bits\stdc++.h:86,
from ..\QueueUsingTemplate.cpp:18:
c:\mingw\lib\gcc\mingw32\6.3.0\include\c++\bits\stl_vector.h:489:7: note: candidate: void >std::vector<_Tp, _Alloc>::assign(std::vector<_Tp, _Alloc>::size_type, const value_type&) [with >_Tp = int; _Alloc = std::allocator; std::vector<_Tp, _Alloc>::size_type = unsigned int; >std::vector<_Tp, _Alloc>::value_type = int]
assign(size_type __n, const value_type& __val)
^~~~~~
Thank you so much VainMan. queryArray.assign(n, T{}); solves the issue. Hi Louis, please find the complete program with include statements here.
/*
* queueUsingArray.cpp
*
* Created on: 02-Nov-2021
* Author: Admin
*/
#include <iostream>
#include <ctype.h>
#include <bits/stdc++.h>
#include <vector>
#include <typeinfo>
#include <type_traits>
using namespace std;
template <class T>
class queueWithArray {
private:
vector<T> queueArray;
int numberOfElements;
int size;
int head;
int tail;
public:
queueWithArray(int n) {
numberOfElements = 0;
head = -1;
tail = -1;
size = n;
queueArray.assign(n,T{});
}
void enqueue(T item) {
if(numberOfElements == size) {
resize(size * 2);
}
if((head == -1) && (tail == -1)) {
head = tail = 0;
} else {
tail = (tail + 1) % size;
}
queueArray[tail] = item;
numberOfElements++;
}
T dequeue() {
T item;
if(numberOfElements == 0) {
cout << "No elements to dequeue" << endl;
} else {
if(numberOfElements == size/4) {
resize(size/2);
}
item = queueArray[head];
if(head == tail) {
head = tail = -1;
} else {
head = (head + 1) % size;
}
numberOfElements--;
}
return item;
}
bool isEmpty() {
return ((head == -1) && (tail == -1));
}
void resize(int newSize) {
if(newSize > 0) {
size = newSize;
int newIndex = 0;
for(int i=head; i<=tail; ++i){
queueArray[newIndex] = queueArray[i];
newIndex++;
}
queueArray.resize(newSize);
head=0;
tail=newIndex-1;
} else {
return;
}
}
void printQueue() {
if(!isEmpty()) {
for(auto i=head; i<tail; i++) {
cout << queueArray[i] << "->";
}
cout << queueArray[tail] << endl;
} else {
cout << "Queue is Empty" << endl;
}
}
};
int main() {
string InputArray[] = {"to", "be", "or", "not", "to", "-", "be", "-", "-", "that", "-", "-", "-", "is"};
queueWithArray<string> obj(2);
for(auto i=0; i < (signed int)(sizeof(InputArray)/sizeof(InputArray[0])); ++i) {
if(InputArray[i] == "-") {
string item = obj.dequeue();
cout << "dequeue->" << item << endl;
} else {
obj.enqueue(InputArray[i]);
cout << "enqueue->" << InputArray[i] << endl;
}
obj.printQueue();
}
int InputArray_int[] = {10,20,30,40,50,-1,20,-1,-1,60,-1,-1,-1,70};
queueWithArray<int> obj_int(2);
for(auto i=0; i < (signed int)(sizeof(InputArray_int)/sizeof(InputArray_int[0])); ++i) {
if(InputArray_int[i] == -1) {
int item = obj_int.dequeue();
cout << "dequeue->" << item << endl;
} else {
obj_int.enqueue(InputArray_int[i]);
cout << "enquque->" << InputArray_int[i] << endl;
}
obj_int.printQueue();
}
return 0;
}
My purpose is to change the tank (an object of first class) by another class (the odometer). So I try to passing by reference, its working when I pass directly object to constructor but its doesn't working when I make an object first then passing object by a method(setOdoIndex). Can someone have a way to do make a method to pass these parameters
#include <iostream>
using namespace std;
class FuelGauge {
protected:
double galls;
double check(double) const;
double checkFuel(double) const;
public:
FuelGauge(double galls){
check(galls);
this->galls = galls;
}
FuelGauge(){
*this = FuelGauge(0);
}
double getFuelLeft() const{
return galls;
}
FuelGauge operator++(){
if (galls > 15) throw "Tank max capacity is 15 gallon";
++galls;
return *this;
}
FuelGauge operator--(){
if (galls == 0) throw "Tank is empty";
--galls;
return *this;
}
void refuel(){
galls = 15;
}
};
double FuelGauge::check(double n) const {
if (n < 0) throw "Dont accepted negative value!";
if (n > 15) throw "Tank max capacity is 15 gallon";
return n;
}
class Odometer{
private:
int odo;
FuelGauge &tank;
void calOdo() {
if (odo > 999999) {odo = 0;};
}
public:
Odometer(int odo, FuelGauge &tank):tank(tank) {
this->odo = odo;
this->tank = tank;
}
Odometer():tank(tank) {
odo = 0;
}
int getOdoIndex() const{
return odo;
}
void setOdoIndex(int odo, FuelGauge &tank) {
this->odo = odo;
this->tank = tank;
}
void carDrive() {
--tank;
calOdo();
++odo;
}
};
int main() {
FuelGauge tank;
cout << "--Fill the tank--" << endl;
try {
for (int i = 0; i < 15; i++) {
++tank;
}
}
catch(const char* e) {
cerr << e << '\n';
}
cout << "\n--Car run--" << endl;
Odometer odo1(0, tank);
try {
for(int i = 0; i < 16; i++) {
cout << "Index of odometer: " << odo1.getOdoIndex() << endl;
cout << "Fuel left: " << tank.getFuelLeft() << endl;
odo1.carDrive();
}
}
catch(const char* e) {
cerr << e << '\n';
}
return 0;
}
I am using VS code for coding in C++. The problem arises when I try to debug a code and set a breakpoint. The local variables pane doesn't show any variables at all. Sometimes it does show some variables but not all of them.
Also when I try to close the debugger and click on the stop button, it does not stop. It requires me to click on it multiple times, which I think means, that multiple debuggers are opened or something like that.
To reproduce this problem, save this text as input_static.txt.
T1 1 2 5
T2 2 4
T3 2 3
T4 1 2 4
T5 1 3
T6 2 3
T7 1 3
T8 1 2 3 5
T9 1 2 3
And debug the following code by setting a breakpoint at line number 201.
#include <bits/stdc++.h>
using namespace std;
ifstream fin;
ofstream fout;
typedef struct fptnode
{
int item, count;
fptnode *next;
map<int, fptnode *> children;
fptnode *parent;
fptnode(int item, int count, fptnode *parent)
{
this->item = item;
this->count = count;
this->parent = parent;
}
} * FPTPTR;
map<int, int> frequency;
bool isMoreFrequent(int a, int b)
{
if (frequency[a] == frequency[b])
return a < b;
return frequency[a] > frequency[b];
}
class FPTREE
{
public:
FPTPTR root;
map<int, list<FPTPTR>> headers;
// map<int, int> frequency;
FPTREE()
{
this->root = new fptnode(-1, 0, NULL);
}
// class isMoreFrequent
// {
// public:
// FPTREE *T;
// isMoreFrequent(FPTREE *T)
// {
// this->T = T;
// }
// bool operator()(int item1, int item2)
// {
// return T->frequency[item1] > T->frequency[item2];
// }
// };
FPTPTR getNewNode(int item, int count, fptnode *parent)
{
FPTPTR T = new fptnode(item, count, parent);
this->headers[item].push_back(T);
return T;
}
void add(vector<int> &transaction)
{
stack<int> S;
std::sort(transaction.begin(), transaction.end(), isMoreFrequent);
for (int i = transaction.size() - 1; i >= 0; i--)
{
S.push(transaction[i]);
}
insert(root, S);
}
int insert(FPTPTR T, stack<int> &S)
{
T->count++;
if (S.empty())
return 0;
int top = S.top();
S.pop();
if (T->children[top] == NULL)
{
T->children[top] = getNewNode(top, 0, T);
}
insert(T->children[top], S);
return 0;
}
void printPreOrder(ofstream &fout)
{
printPreOrder(fout, this->root);
}
void printPreOrder(ofstream &fout, FPTPTR T)
{
if (T)
{
fout << "[" << T->item << ", " << T->count << "]" << ' ';
for (auto p : T->children)
{
printPreOrder(fout, p.second);
}
}
}
void printTree(ofstream &fout)
{
printTree(fout, this->root);
}
void printTree(ofstream &fout, FPTPTR T, int level = 0)
{
if (T)
{
for (int i = 0; i < level; i++)
fout << "\t";
fout << "[" << T->item << ", " << T->count << "]" << endl;
for (auto p : T->children)
{
printTree(fout, p.second, level + 1);
}
}
}
void generatePath(FPTPTR node, vector<int> &path)
{
if (node && node->item >= 0)
{
path.push_back(node->item);
generatePath(node->parent, path);
}
}
FPTREE newTree(int item)
{
list<FPTPTR> &nodes = this->headers[item];
vector<int> patternBase;
FPTREE f;
for (auto node : nodes)
{
patternBase.clear();
generatePath(node->parent, patternBase);
for (int j = 0; j < node->count; ++j)
f.add(patternBase);
}
return f;
}
int clear()
{
return this->clear(this->root);
}
int clear(FPTPTR T)
{
for (auto p : T->children)
{
clear(p.second);
}
return 0;
}
bool isEmpty()
{
// return this->root->count == 0;
return this->root->children.empty();
}
} F;
ofstream tempout;
map<set<int>, int> mine(FPTREE f, int r = -1)
{
map<set<int>, int> M;
if (!f.isEmpty())
{
// if (f.root->children.empty())
// M[{}] += f.root->count;
tempout << "\nOn removing " << r << ":\n";
f.printTree(tempout);
for (auto p : frequency)
{
FPTREE subF = f.newTree(p.first);
map<set<int>, int> m = mine(subF, p.first);
for (auto q : m)
{
auto itemset = q.first;
itemset.insert(p.first);
M[itemset] += q.second;
}
subF.clear();
}
return M;
}
// tempout << "\nTerminated.\n";
return {};
}
int main(int argc, char const *argv[])
{
fin.open("input_static.txt");
fout.open("output_static.txt");
tempout.open("temp");
string str, s;
while (fin >> s)
{
if (s.front() != 'T')
{
frequency[stoi(s)]++;
}
}
vector<int> transaction;
stringstream st;
fin.clear();
fin.seekg(0);
while (std::getline(fin, str))
{
st.clear();
st.str(str);
transaction.clear();
while (st >> s)
{
if (s.front() != 'T')
{
transaction.push_back(stoi(s));
}
}
F.add(transaction);
}
fout << "Preorder:\n";
F.printPreOrder(fout);
fout << endl
<< endl;
fout << "Tree in directory form:\n";
F.printTree(fout);
// printPrefixes(5);
map<set<int>, int> frequentItemsets = mine(F);
fout << endl;
for (auto p : frequentItemsets)
{
fout << "Frequency=" << p.second << "\t";
for (int item : p.first)
{
fout << item << ' ';
}
fout << endl;
}
// for (int i = 1; i <= 5; ++i)
// {
// fout << i << ":\n";
// FPTREE f = F.newTree(i);
// f.printTree();
// }
// F.newTree(1).newTree(2).printTree(fout);
return 0;
}
If it helps this is a program to generate and mine an FP-tree to find frequent itemsets in a transactional database.
We have been restricted us to not use a loop in a program as a programming challenge.
Restrictions:
You can not use while, for, goto and recursion.
The restrictions are pretty daunting. I couldn't really think of any proper solution.
So I opted for this one which is achieved by modifying the return address.
Could this be any better?
#include <unistd.h>
#include <sys/mman.h>
#include <iostream>
#include <cstring>
void the__(){}
void magic__(){}
void loop__(){}
void function__(){}
void here__(){}
template <typename T>
struct for_
{
bool started = false;
void* fix = nullptr;
void(*body)(T&) = nullptr;
for_(void(*body)(T&))
: body(body)
{
auto do_for__ = uintptr_t(do_for_);
uint64_t magic[] = {5243466812662057800, 6135086863767628931ull, 10416984888688609608ull, 144};
mprotect((void*)(do_for__-do_for__%4096), 4096, 7);
std::memcpy((void*)(do_for__+135), magic, 25);
}
static void do_for_(T& ctx)
{
void** p = (void**)((char*)&p+16);
if (!ctx.started)
{
if (!ctx) return;
ctx.started = true;
ctx.fix = *p;
*p = (void*)do_for_;
}
ctx.body(ctx);
ctx.next();
if (ctx)
{
the__();
magic__();
loop__();
function__();
here__();
}
else
{
*p = ctx.fix;
}
}
};
struct For0ToN : for_<For0ToN>
{
For0ToN(int N, void(*f)(For0ToN&))
: for_<For0ToN>(f)
, N(N)
{
do_for_(*this);
}
operator bool() {return i < N;}
operator int() {return i;}
void next() {i++;}
int count() {return i;}
int i = 0, N = 0;
};
int main()
{
For0ToN(10, +[](For0ToN& i)
{
std::cout << int(i) << ": ";
For0ToN(i.count(), +[](For0ToN& i)
{
std::cout << int(i) << ". ";
});
std::cout << "\n";
});
std::cout << "done\n";
return 0;
}
The code is demonstrated here: https://coliru.stacked-crooked.com/a/3dd77ade501ac748
You could use longjmp. Here's an example from cppreference:
#include <csetjmp>
#include <iostream>
std::jmp_buf jump_buffer;
[[noreturn]] void a(int count)
{
std::cout << "a(" << count << ") called\n";
std::longjmp(jump_buffer, count+1); // setjmp() will return count+1
}
int main() {
// loop from 0-9
volatile int count = 0; // local variables must be volatile for setjmp
if (setjmp(jump_buffer) != 10) {
a(count++); // This will cause setjmp() to exit
}
}
Question is unclear but 1 alternative of the loop is std::transform()
Template metaprogramming is common way of avoiding writing explicit loop in code. This work gets done by compiler. Check this for examples of factorial and bubble sort implementation without writing explicit loops. You can check this stack overflow post as well.
Does it count if I hide recursion into function objects and create a finite state machine?
struct state
{
size_t current_column;
size_t current_row;
size_t max_column;
size_t max_row;
};
typedef function<void(state&)> action_t;
struct do_item
{
do_item(ostream& ss, action_t* move_next)
: ss_(ss), move_next_(move_next) {}
void operator()(state& s)
{
if (s.current_row == s.max_row)
{
ss_ << "done";
return;
}
if (0 == s.current_column)
{
ss_ << s.current_row << ':';
}
if (s.max_column == s.current_column)
{
ss_ << '\n';
s.current_column = 0;
++s.current_row;
s.max_column = s.current_row;
}
else
{
ss_ << ' ' << s.current_column << '.';
++s.current_column;
}
(*move_next_)(s);
}
ostream& ss_;
action_t* move_next_;
};
static string no_loops_challenge(size_t n)
{
stringstream ss;
state s = {0, 0, 0, n};
action_t move_next;
do_item action(ss, &move_next);
move_next = action;
action(s);
return ss.str();
}
Here's a solution using range-v3 that should satisfy all the constraints:
namespace rv = ranges::views;
ranges::for_each(rv::iota(0, 10), [](int i) {
std::cout << i << ": ";
ranges::copy(rv::iota(0, i),
ranges::ostream_iterator<int>(std::cout, ". "));
std::cout << "\n";
});
Here's a demo.
[INFO]
I'm new here and... new to programming. I'm learning C (with very little of C++) for about a year and now I'm stuck. I'm currently writing my first bigger application for training purposes and as every programist - I'm trying to be as lazy as I could. My application is based on Simple Fast Multimedia Library (SFML) for drawing graphics and of course C/C++ for logic. I was tired of having lots of different variables hidden in code (like Window Resolution, Window Position etc.) soo I started writing class for reading *txt files with configuration (You know: config.ini with something like "iWindowResolutionX=1920;"). Algorythm that opens *txt files, interprets them and pulls out needed data is working (proppably it is very bad - but hey, it is working :P)
[QUESTION]
I'm stuck with very basic thing.
I have object of my config file reader class and I want to achieve something like this:
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.
And here I am stuck. How to force method to return different basic data types( char, int, float etc. )?
}
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) and then errors about trying to return different datatypes than firstly selected (this is simple, if compiler see "return value" for the first time, it can't allow me to return any other datatype).
Next thing I've tried was template methods, but I'm to stupid to understand it ;)
Ok, there is simple solution - I can copy my Search method X times for X datatypes I want and just simply overload it - but this is not elegant solution and won't teach me anything new. Below my code:
"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
Anyone can point me out how to convert Search method for being able to either return different datatypes:
int main()
{
int value_1 = 0;
CfgReader Config("config.ini");
value_1 = Config.Search("iBitDepth");
return 0;
}
or work as here: (CfgReader object gets reference to variable as a parameter)
int main()
{
int value_1 = 0;
CfgReader Config("config.ini");
Config.Search("iBitDepth", &value_1);
return 0;
}
If someone could also give me a example on how to properly convert my Search method for template method.
Thanks for responces, I'm out of ideas...
I'd suggest to implement separate methods for each data type.
You know data type of the target variable, right? Then you can do few methods like this:
int GetInt(const char* name, int defaultValue = 0) const;
std::string GetString(const char* name, const char* defaultValue = "") const;
And call appropriate method:
int bitDepth = config.GetInt("Window.iBitDepth", 24);
One way to do this using templates is to use "lexical cast" (as Boost calls it). Implementing simple lexical cast function using std::istringstream is relatively simple:
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;
}
This will work for all types for which operator >> is overloaded, which includes primitive types, such as float or int. Additionally, you can overload the operator for your custom types.
With this, you can implement Search template method which converts a string to requested type:
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)
Personally, I don't use VS too often, but I suppose this means that compiler must see body (definition) of the method when you call it. This is necessary - after all, when using auto (without trailing return type), compiler has to deduce returned type based on body of the function.