C++ enum question.
So I have a list of files, and their IDs that I need to iterate over, and do stuff to. Most of the stuff is the same, but there are a few file-specific things that need to be done. I tried putting the file IDs in an enum, and iterating over that. Howver, the fileIDs are non contiguous, and jump around.
Currently, I have something akin to this
for(int i = 0; i < FILE_ENUM_MAX; i++)
{
currentFile = myEnum(i);
// do stuff
}
enum myEnum {
file1 = 0x1111,
file2 = 0x8000,
file3 = 0x75,
file4 = 0x120,
FILE_ENUM_MAX = 4
}
This doesn't work; I just go through files 0, 1, 2, and 3. I get the idea that I can't just get the Nth item in an enumeration by asking for item N. So what would be the best way to iterate over this enum? Or should I just get rid of it? I probably could put the items in numerical order, but I'd prefer a solution to where order didn't matter.
Unfortunately, C++ does not provide a way to iterate through enums like you want.
I guess the low-tech answer might be to skip the enum, and just create a static array:
#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
int FILE_ENUM[] = { 0x1111, 0x8000, 0x75, 0x120 };
for(int i = 0; i < ARRAYSIZE(FILE_ENUM); i++) {
currentFile = myEnum[i];
// do stuff
}
TJ
I have two suggestions:
Use a std::vector to contain the enums.
Use a std::map to contain the
enums.
Solution 2 offers a benefit where the key is the file ID and the value can be the name of the file (or an object containing attributes of the file, such as a file handle or pointer).
i <= FILE_ENUM_MAX and it will iterate with 4th file. Sorry if this is an old thread but maybe someone will still need an answer trying to find it here.
Related
What is the best way to organize the following into a for loop that iterates X times, but requires updating the variables (velocity, currentPose, targetPoint) depending on the iteration number?
velocity1 = computeVelocity(currentPose1, targetPoint1);
velocity2 = computeVelocity(currentPose2, targetPoint2);
...
velocityX = computeVelocity(currentPoseX, targetPointX);
The for loop would ideally look something like this:
for (int i=0; i<X; i++)
{
velocity_i = computeVelocity(currentPose_i, targetPoint_i);
}
Since for each velocity, there will be an associated (and possibly distinct) currentPose and targetPoint, one way to do it it to have all these variables as std::vectors, or std::array if you know at compile time how many items you will have to store. Then your loop could look like this:
for (int i=0; i<X; i++)
{
velocity[i] = computeVelocity(currentPose[i], targetPoint[i]);
}
I don't think that wanting the i to be a part of the variables' name is doable (although there might be some way to do it using preprocessor macros and the # concatenation operator, I have not thought about it), nor would it be usual C++ code.
For a C++ programmer the vector/array approach is the more natural one.
I want to have the ability to update over 100 labels, so I was going to put them in an array like this:
voltage_label_array[0] = this->ui->Voltage_0;
voltage_label_array[1] = this->ui->Voltage_1;
voltage_label_array[...] = this->ui->Voltage_2;
voltage_label_array[...n] = this->ui->Voltage_n;
and then have this method
void MainWindow::updateValue(int i, int voltage){
voltage_label_array[i]->setText(QString::number(voltage));
}
but having 100 lines to set this up seems like a bad idea. Is there a way I can initialize a QLabel array inside a for loop or something?
If you need to do this, something is horribly wrong with your design. But it is possible.
Assuming your labels are named Voltage_0 to Voltage_99:
for(int i = 0; i < 100; ++i) {
auto ptr = this->findChild<QLabel*>(QString("Voltage_%1").arg(i));
voltage_label_array[i] = ptr;
}
This "solution" uses Qt's runtime reflection and carries the expected performance penalties.
But if you need to display several similar values, look up QListWidget and similar classes.
I am trying to create a simple loop that calls data from sequential channels. I have channels numbered 1-8 (named qL1 - qL8) and need to call the qL*->Draw(); command for all of them.
Is there a way to use a loop to continually update the number in the command? I believe the equivalent code in a c shell would be:
for {set i 1} {$i <= 8} {incr i} {
qL$i->Draw();
}
As stated in the title, I am trying to write a macro for ROOT. Thanks.
put everything into an array/vector
well, you can fill your channels (I assume TH1 here, but it should work similarly for TGraph, TTree, etc) into an array/vector first, since they are pointers anyhow:
TH1* qL[9]; // nine elements to have indices matching
qL[1] = qL1;
qL[2] = qL2;
qL[3] = qL3;
qL[4] = qL4;
qL[5] = qL5;
qL[6] = qL6;
qL[7] = qL7;
qL[8] = qL8;
for (int i = 1 ; i <= 8 ; i++) { qL[i]->Draw() ; }
though that probably doesn't gain you much.
use ROOT's directory mechanism and use string manipulation
What might be better suited is to work with root's directory management (if you anyhow get your channels from an input file, that should be a straight forward solution):
for (int i = 1 ; i <= 8 ; i++) {
TH1* localhist = (TH1*) gDirectory->Get(Form("qL%d",i));
localhist->Draw();
}
Here, Form(...) is a cstring and the syntax for Form is the same as for printf (google is your friend). And Get looks for an object of which the name is the cstring provided. (be aware of the room for confusion in TH1* variablename = new TH1F( NAME, TITLE , ...), what matters is the NAME and not the variablename)
preprocessor macros
you can use a preprocessor (e.g. boost) to concatenate the string part (qL) of your variable with a number and use this in a preprocessor macro which takes the number as argument.
#include <boost/preprocessor/cat.hpp>
#define qL(i) BOOST_PP_CAT(qL, i)
TH1* qL1 = new TH1F("test","test",1,0,1);
qL(1)->GetName();
The problem with this is, that the argument must be known at compile time, if you put this in a for loop, you'll get errors because qLi is not known.
Which can be done in preprocessor, though not sure if this will greatly work out on the long run
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#define HHHHH(z,n,zz) BOOST_PP_CAT(qL, n) zz
BOOST_PP_REPEAT_FROM_TO(1,3,HHHHH,->Draw();)
No. If only your channels names were an array, e.g. qL[N], where N=0, 1, ..., 7, that would be possible with something like
for (Int_t i=0; i<8; i++)
{
qL[i]->Draw();
}
I'm just getting started with HDF5 and would appreciate some advice on the following.
I have a 2-d array: data[][] passed into a method. The method looks like:
void WriteData( int data[48][100], int sizes[48])
The size of the data is not actually 48 x 100 but rather 48 x sizes[i]. I.e. each row could be a different length! In one simple case I'm dealing with, all rows are the same size (but not 100), so you can say that the array is 48 X sizes[0].
How best to write this to HDF5?
I have some working code where I loop through 0 to 48 and create a new dataset for each row.
Something like:
for (int i = 0; i < 48; i++)
{
hsize_t dsSize[2];
dsSize[0] = 48;
dsSize[1] = sizes[0]; // use sizes[i] in most general case
// Create the Data Space
DataSpace dataSpace = DataSpace(2, dsSize);
DataSet dataSet = group.createDataSet(dataSetName, intDataType, dataSpace);
dataSet.write(data[i], intDataType);
}
Is there a way to write the data all at once in one DataSet? Perhaps one solution for the simpler case of all rows the same length, and another for the ragged rows?
I've tried a few things to no avail. I called dataSet.write(data, intDataType), i.e. I threw the whole array at it. I seemed to get garbage in the file, I suspect because the array the data is stored in is actually 48x100 and I only need a small part of that.
It occurred to me that I could maybe use double ptrs int** or vector> but I'm stuck on that. As far as I can tell, "write" need a void* ptr. Also, I'd like the file to "look correct". I.e. one giant row with all rows of data is not desirable, if I must go that route, someone would need to communicate a slick way to store the info that would allow me to read the data back in from file (perhaps store row lengths as attributes?).
Perhaps my real problem is finding C++ examples of non-trivial use cases.
Any help is much appreciated.
Dave
Here is how you can do it using variable length arrays if your data is a vector of vectors (which seems to make sense for your use case):
void WriteData(const std::vector< std::vector<int> >& data)
{
hsize_t dim(data.size());
H5::DataSpace dspace(1, &dim);
H5::VarLenType dtype(H5::PredType::NATIVE_INT);
H5::DataSet dset(group.createDataSet(dataSetName, dtype, dspace));
hvl_t vl[dim];
for (hsize_t i = 0; i < dim; ++i)
{
vl[i].len = data[i].size();
vl[i].p = &data[i][0];
}
dset.write(vl, dtype);
}
right now im trying to make a function that checks to see if the user’s selection is already in the array , and if it does itll tell you to choose a diff number. how can i do this?
Do you mean something like this?
bool CheckNumberIsValid()
{
for(int i = 0 ; i < array_length; ++i)
{
if(array[i] == user_selection)
return false;
}
return true;
}
That should give you a clue, at least.
What's wrong with std::find? If you get the end iterator back, the
value isn't in the array; otherwise, it is. Or if this is homework, and
you're not allowed to use the standard library, a simple while loop
should do the trick: this is a standard linear search, algorithms for
which can be found anywhere. (On the other hand, some of the articles
which pop up when searching with Google are pretty bad. You really
should use the standard implementation:
Iterator
find( Iterator begin, Iterator end, ValueType target )
{
while ( begin != end && *begin != target )
++ begin;
return begin;
}
Simple, effective, and proven to work.)
[added post factum]Oh, homework tag. Ah well, it won't really benefit you that much then, still - I'll leave my answer since it can be of some use to others browsing through SO.
If you'd need to have lots of unique random numbers in a range - say 45000 random numbers from 0..45100 - then you should see how this is going to get problematic using the approach of:
while (size_of_range > v.size()) {
int n = // get random
if ( /* n is not already in v */ ) {
v.push_back(n);
}
}
If the size of the pool and the range you want to get are close, and the pool size is not a very small integer - it'll get harder and harder to get a random number that wasn't already put in the vector/array.
In that case, you'll be much better of using std::vector (in <vector>) and std::random_shuffle (in <algorithm>):
unsigned short start = 10; // the minimum value of a pool
unsigned short step = 1; // for 10,11,12,13,14... values in the vector
// initialize the pool of 45100 numbers
std::vector<unsigned long> pool(45100);
for (unsigned long i = 0, j = start; i < pool.size(); ++i, j += step) {
pool[i] = j;
}
// get 45000 numbers from the pool without repetitions
std::random_shuffle(pool.begin(), pool.end());
return std::vector<unsigned long>(pool.begin(), pool.begin() + 45000);
You can obviously use any type, but you'll need to initialize the vector accordingly, so it'd contain all possible values you want.
Note that the memory overhead probably won't really matter if you really need almost all of the numbers in the pool, and you'll get good performance. Using rand() and checking will take a lot of time, and if your RAND_MAX is equal 32767 then it'd be an infinite loop.
The memory overhead is however noticeable if you only need few of those values. The first approach would usually be faster then.
If it really needs to be the array you need to iterate or use find function from algorithm header. Well, I would suggest you go for putting the numbers in a set as the look up is fast in sets and handy using set::find function
ref: stl set
These are some of the steps (in pseudo-code since this is a homework question) on how you may get around to doing this:
Get user to enter a new number.
If the number entered is the first, push it to the vector anyway.
Sort the contents of the vector in case size is > 1.
Ask user to enter the number.
Perform a binary search on the contents to see if the number was entered.
If number is unique, push it into vector. If not unique, ask again.
Go to step 3.
HTH,
Sriram.