TMap or std::map problems

I want to make something like a python-style dictionary where I can associate an integer (a particle’s lund number) to a string (which holds the particle’s name). Something like name[11] = “Electron”, name[211] = “Pion”, etc. The purpose is that given an integer, I can look up the associated string.

I’ve read many posts and pages about how to do this properly, but it seems nothing actually is straightforward. Typing things into the interpreter, I can make an std::map which holds the data that I want, but then I can’t use name.find(11), the iterator that is returned is claimed to be unknown by CINT (like this post Using std::map in a ROOT macro). When I try to put that #pragma line from the post, nothing changes.

When I try to compile the code instead, I can no longer do assignments like name[11] = TString(“Electron”), I get an error message saying “C++ requires a type specifier for all declarations” even though all the elements are declared. I also tried declaring the TString elname(“Electron”) and assigning name[11] = elname, but I get the same error.

I also learned that I can’t use a built-in TMap because one of my keys is an integer. I tried using instead a TString holding a string version of the integer that I want, but it says it can’t call TMap::Add in the current scope, and the documentation on TMap is rather terse.

Any suggestions on how to proceed? Would it be easiest to use two vectors of equal length, one for the integers and one for the strings? Its inelegant and I need to trust myself to keep them tidy, and I would not be able to use any builtin .find() methods to find the string associated with a given integer.

Thanks for suggestions,
Jean-François

Hi,

perhaps redundant, but there is already class TDatabasePDG, an instance of which will allow you to get to 11 being ‘e-’ (not quite what you want, but perhaps close enough).

That said, the insertions work fine for me (root.exe trunk; it auto-generates the map dictionary). Which version of ROOT are you using? And what map do you declare? Do you have all #include’s that are needed?

With the autogen dict, the find() does indeed not work (it returns something, but the something is not usable). Of course, given that the particle ids are fixed, and given that a non-existing id will yield the empty string when using the indexing operator, perhaps it’s an option to use name[id] instead of name.find(id)?

Cheers,
Wim

My code is stuck inside the result from MakeSelector(), but anyways I get the same error message when I try a pared-down macro:

#include <map>
#include "TString.h"
std::map<int,TString> name;

name[11] = TString("El");
name[13] = TString("Mu");

This works fine when I copy & paste it into the interpreter, but it does not compile if I try to .L testmap.C+, I get the error messages:

[quote]Info in TUnixSystem::ACLiC: creating shared library /Users/jfcaron/Projects/QA/./testmap_C.so
Error: improper lvalue testmap.C:5:
Error: improper lvalue testmap.C:6:
Warning: Error occurred during reading source files
Warning: Error occurred during dictionary source generation
!!!Removing /Users/jfcaron/Projects/QA/testmap_C_ACLiC_dict.cxx /Users/jfcaron/Projects/QA/testmap_C_ACLiC_dict.h !!!
Error: /Users/jfcaron/Software/root/bin/rootcint: error loading headers…
Error in : Dictionary generation failed!
Info in : Invoking compiler to check macro’s validity
/Users/jfcaron/Projects/QA/./testmap.C:5:1: error: C++ requires a type specifier for all declarations
name[11] = TString(“El”);
^~~~
/Users/jfcaron/Projects/QA/./testmap.C:6:1: error: C++ requires a type specifier for all declarations
name[13] = TString(“Mu”);
^~~~
2 errors generated.
[/quote]

I tried adding this below my #includes:

#ifdef __MAKECINT__ #pragma link C++ class std::map<int,TString>+; #endif
but I admit I don’t know what that code does, so I’m not sure how it’s supposed to help.

I am using Root 5.31/01 on a Mac, compiled via MacPorts.

Jean-François

[code]#include “TString.h”
#include

std::map<int,TString> name; // “name” is a global variable …

void testmap(void) {
// std::map<int,TString> name; // … or … “name” is a local variable

name[11] = TString(“El”);
name[13] = TString(“Mu”);

return;
}[/code]

[quote=“wlav”]Hi,

perhaps redundant, but there is already class TDatabasePDG, an instance of which will allow you to get to 11 being ‘e-’ (not quite what you want, but perhaps close enough).

That said, the insertions work fine for me (root.exe trunk; it auto-generates the map dictionary). Which version of ROOT are you using? And what map do you declare? Do you have all #include’s that are needed?

With the autogen dict, the find() does indeed not work (it returns something, but the something is not usable). Of course, given that the particle ids are fixed, and given that a non-existing id will yield the empty string when using the indexing operator, perhaps it’s an option to use name[id] instead of name.find(id)?

Cheers,
Wim[/quote]

I’m having a similar problem and I think the issue is not with the dictionary of std::map but with the dictionary of the iterator.

Find returns the iterator to the required object in the map. In compiled code it works fine, when I try to run it as a script I got:
Error: Symbol it is not defined in the current scope sourcename:line
Error: Failed to evaluate it->second
[…]
where it is the name of an object of type std::map<int, MyClass>::iterator
both MyClass and map<int, MyClass> are defined in the linkDef file.

The direct access operator [ ] works fine but it’s not advisable to use it without caution because if the operator [ key ] do not find the element at key it will add it and this is something that you probably do not want

Even including the link to map<int, MyClass>::iterator the script do not work.

Any idea?

Hi,

Can you provide a running example showing the problem?

Philippe.

Dear Philippe
Sorry I didn’t answered before, I thought you were automatically subscribed to the post you contribute to and I was waiting for a mail notice.
Anyway I think I solved the problem adding in the linkdef file the following lines I found insome of the autodict generated by root:

[quote]#pragma link C++ class MyClass+; //Already present
#pragma link C++ class map<int, MyClass>+; //Already Present
#pragma link C++ class map<int, MyClass>::*;
#pragma link C++ operators map<int, MyClass>::iterator; //Already present
#pragma link C++ operators map<int, MyClass>::const_iterator;
#pragma link C++ operators map<int, MyClass>::reverse_iterator;[/quote]

The lines I commented with already present wre the ones in the not working example where the error was that it couldn’t find the type pair<int, MyClass> which is contained inside the map and should be included in the dictionary with the third line of the code