Globals

V

Victor Bazarov

Victor Bazarov said:
string& operator[](string const& idx) { return config[idx]; }

(returns a reference and takes a reference to const).

Ah ok I see, but why return the reference to the string also?

You're assigning to it, aren't you? And you want the assignment to
stick, don't you? So, returning a temporary is OK if you don't care
that the value you assign isn't stored in the map itself and basically
immediately forgotten after the temporary goes away.
Well it would also work, but with a class for example I can initialize
the values from the configuration file directly in the constructor of
the class...

Yes, or you could simply have a static dummy object that would
initialize your map, like so:

int dummy = GLOBALS_initializer_function(); // namespace scope

And fill up your GLOBALS map in that function... Of course, there is
always the static object initialization fiasco you need to worry about.
Make sure no static objects ever use your GLOBALS before it's
constructed (in case you go with the class) or filled in (if you go with
the initialization function).

V
 
J

Juha Nieminen

Victor Bazarov said:
Why do you really need a class? Why can't you simply do

extern std::map<std::string,std::string> GLOBALS;

One advantage of using a class is that if it ever happens in the future
that you need to eg. duplicate all the variables (eg. to make a "snapshot"
to which you can return later), it becomes much easier and simpler.
 
A

Andrea Crotti

Victor Bazarov said:
You're assigning to it, aren't you? And you want the assignment to
stick, don't you? So, returning a temporary is OK if you don't care
that the value you assign isn't stored in the map itself and basically
immediately forgotten after the temporary goes away.

Uhm well I tried with the following
string& operator[](const string& key) { return conf[key]; }
string operator[](string& key) { return conf[key]; }
string operator[](const string& key) { return conf[key]; }

and in all the three cases it works in the same way, if I assign
something I also find it after...
Yes, or you could simply have a static dummy object that would
initialize your map, like so:

int dummy = GLOBALS_initializer_function(); // namespace scope

And fill up your GLOBALS map in that function... Of course, there is
always the static object initialization fiasco you need to worry
about. Make sure no static objects ever use your GLOBALS before it's
constructed (in case you go with the class) or filled in (if you go
with the initialization function).

V

Interesting the fiasco, but well a static object will always call a
constructor before going further?
Or should I just have another function "initialize()" and make sure it's
called before I start to read?

Globals.h:
extern Globals CONF;

class Globals
{
Globals::Globals() {...}
};

and in Globals.cpp there is

Globals CONF;

Would that be already enough to avoid the fiasco?
Or as they say on the FAQ should I create a function which creates this
global object (not so important if I can't clear it)??

And now instead another problem, supposing I have the following
parameters.

--8<---------------cut here---------------start------------->8---
int x;
long y;
str::vector<string> z;
--8<---------------cut here---------------end--------------->8---

the idea was to use a mapping to avoid repetition in the assignment from
the ini file, so that I can just do

CONFIG["x"] = 100;
And use a for loop on the map.

BUT I only read strings in the ini file, and I have to convert the
values somehow.
So the best thing would be to have a something like

{ x : (value, function),
y : (value, function)
}

and then call the corresponding function.
Or what other data structure would be good?

How can I do that? Maybe a function pointer, like:

{ x : ("0", &atoi), ...}
which then calls the right function before actually assigning something.
Or how else can I do to accomplish this?

PS. use boost unfortunately is not an answer since I can't (at least for
this part of the project
 
V

Victor Bazarov

Victor Bazarov said:
You're assigning to it, aren't you? And you want the assignment to
stick, don't you? So, returning a temporary is OK if you don't care
that the value you assign isn't stored in the map itself and basically
immediately forgotten after the temporary goes away.

Uhm well I tried with the following
string& operator[](const string& key) { return conf[key]; }
string operator[](string& key) { return conf[key]; }
string operator[](const string& key) { return conf[key]; }

and in all the three cases it works in the same way, if I assign
something I also find it after...

You do? Weird. I would expect that the two latter cases wouldn't work...
Interesting the fiasco, but well a static object will always call a
constructor before going further?

Not sure what you mean by 'going further'? Read the FAQ.
Or should I just have another function "initialize()" and make sure it's
called before I start to read?

I am not convinced that it's going to help. Read the FAQ.
Globals.h:
extern Globals CONF;

class Globals
{
Globals::Globals() {...}
};

and in Globals.cpp there is

Globals CONF;

Would that be already enough to avoid the fiasco?

May not be. Read the FAQ.
Or as they say on the FAQ should I create a function which creates this
global object (not so important if I can't clear it)??

Well, since you already read the FAQ, follow its suggestions.
And now instead another problem, supposing I have the following
parameters.

You better start another thread.
--8<---------------cut here---------------start------------->8---
int x;
long y;
str::vector<string> z;
--8<---------------cut here---------------end--------------->8---

the idea was to use a mapping to avoid repetition in the assignment from
the ini file, so that I can just do

CONFIG["x"] = 100;
And use a for loop on the map.

Huh? Are you assuming I know the details of what you're trying to do
just as well as you do?
BUT I only read strings in the ini file, and I have to convert the
values somehow.

Converting strings is a very common problem, and there are tons of
available solutions, even in public domain, I am sure.
So the best thing would be to have a something like

{ x : (value, function),
y : (value, function)
}

To have it WHERE? Are you aware we're not mind readers?
and then call the corresponding function.
Or what other data structure would be good?

I dunno.
How can I do that? Maybe a function pointer, like:

{ x : ("0",&atoi), ...}
which then calls the right function before actually assigning something.
Or how else can I do to accomplish this?

Better see if you can find some kind of open source solution for
PS. use boost unfortunately is not an answer since I can't (at least for
this part of the project

You can't what?

V
 
A

Andrea Crotti

Victor Bazarov said:
You do? Weird. I would expect that the two latter cases wouldn't work...

Why not? The [] operator of the dictionary copy the value inside and it
should be all it needs, isn't it?
Well, since you already read the FAQ, follow its suggestions.

Ok I'll use a function than, thanks.
Better see if you can find some kind of open source solution for
processing a file that is either XML (modern) or <name>=<value> pair,
I am sure that you can find it. GIYF

I rephrase the problem.
First I can't really use external libraries (otherwise I would use many
things from boost) considering where this code will be compiled and
deployed.

Second I have already a ini parser which works already for what I need,
the only problem is that I would like to avoid code duplicatioin.

I mean, I want to be able to fill a dictionary like

var1 : value1
var2 : value2

from the strings that I'm reading with the config parser, but what I
have to do now is.

CONFIG["var1"] = atoi(value2.c_str())

and so on, specifying the conversion function every time.
If instead I'm able to also pass a pointer to the conversion function
INTO the map, then I would be able to loop like

for key in config.keys:
config[key][0] = config[key][1](value..)

So the question were:
- what structure should I use to keep the two different mappings (var->
value, var -> function pointer)
- should I use function pointers in a C-like way? But what do I gain if
I don't know a priori what's the return value type?
Maybe I need a template then?

hope this it's more clear now..
 
A

Andrea Crotti

Victor Bazarov said:
What does the conversion function depend on? The type of the
argument? Does that come from the name itself? Like 'var1' shall
always be an int and that's why you can use 'atoi'? How does it work
if there "value" cannot be converted to an int?

That's the point, there can be many possible types, that's why I need a
mapping
"varname" -> "function_from_string_to_T" (where T is the type of
varname)

Because the thing is that from the configParser I only get strings or a
list of strings.
Maybe I should pass the mapping (variable_name, type) to the
ConfigParser so I'm sure that I already get the right values and I can
also do some checking on the values.
Why do you have two different mappings? You can always have a
function that returns its argument, can't you? You can even overload
it:

std::string pass_through(std::string const& s) { return s; }
int pass_through(int i) { return i; }

or simply use a template:

template<class T> T pass_through(T const& t) { return t; }

(your types need to be copy-constructible).

Then you simply use that function instead of 'value' in your former
"mapping" to make everything uniform.


This I really don't get, what can be used for a function that returns
the object itself without any conversion?
 
A

Andrea Crotti

I thought I had a good idea but still doesn't work.

I tried to overload the operator[] directly in the ConfigParser, giving
back the right return type.

Since I don't need many types it's not a problem and I have something
like

--8<---------------cut here---------------start------------->8---
int operator[](const string&);
vector<string> operator[](const string&);
--8<---------------cut here---------------end--------------->8---

implemented as

--8<---------------cut here---------------start------------->8---
int ConfigParser::eek:perator[](const string& key)
{
return atoi(conf[key].c_str());
}

vector<string> ConfigParser::eek:perator[](const string& key)
{
return split(conf[key], ' ');
}
--8<---------------cut here---------------end--------------->8---

The problem is that with 1 it works perfectly, but with more than 1 it's
not allowed

--8<---------------cut here---------------start------------->8---
ConfigParser.hpp:24: error: ‘std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > ConfigParser::eek:perator[](const std::string&)’ cannot be overloaded
ConfigParser.hpp:23: error: with ‘int ConfigParser::eek:perator[](const std::string&)’
make: *** [Beacon.o] Error 1
--8<---------------cut here---------------end--------------->8---

but why I don't get it?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,781
Messages
2,569,619
Members
45,316
Latest member
naturesElixirCBDGummies

Latest Threads

Top