Say I create an enum but eventually someone wants to add items to that enum, what does one do?
ex:
// blah.hpp
enum PizzaDressing {
DRESSING_OLIVES = 0,
DRESSING_CHEESE = 1
};
and in my FunkyPizza class, there might be pepper toppings.
So how could I add peppers without obviously modifying the original enum?
Thanks.
This is closest to what you want: Base enum class inheritance
Since enums are typically handled as some size of int in the compiler, all you have to do is later make
enum PizzaDressing
{
Olives = 0,
Cheese = 1,
Pepperoni = 2
};
or you could allow it to count
enum PizzaDressing
{
Olives = 0,
Cheese = 1,
Pepperoni
};
You could, if neither of those is acceptable for some reason, use math (Cheese + 1).
You can play around with the enum in almost any way you could with a numeric value.
Note that the enumerator you use is typically baked into the code by the compiler, it doesn't show up as its name, simply value. Thus, modifying (extending) the enumerator later on will not effect code that has been built.
I think it's legal syntax to use an enumeration in another enumerator, with casts, but I've never tried it. This may work, but is kind of ugly:
enum PizzaDressing
{
Olives = 0,
Cheese = 1
};
enum OtherPizzaDressings
{
Start = (OtherPizzaDressings)PizzaDressing::Cheese;
Pepperoni
};
That would be known as a "dynamic enum". To the best of my knowledge, nothing like this exists in C++. However, since we're using C++ and not C, you could do something like this:
#include <string>
#include <map>
std::map<std::string, int> myMap;
myMap["DRESSING_OLIVES"] = 0;
myMap["DRESSING_CHEESE"] = 1;
myMap["PEPPER_TOPPING"] = 2;
You can't dynamically modify an enum, because it only defines a new type resolved at compile time. They are mnemonics for the programmer, at compilation they are translated to numbers.
That said, you can use any number not used by the original enum to represent whatever you want:
PizzaDressing a;
a = (PizzaDressing)5;
Related
When would it be better to proceed this way
#define PREFIX_IDX 0
#define SUFFIX_IDX 1
#define ARRAY_DATA_SIZE 2
int data[ARRAY_DATA_SIZE ] = 0;
int main() {
data[PREFIX_IDX] = 6;
data[SUFFIX_IDX] = 19;
return 0;
}
compared with
#define ARRAY_DATA_SIZE 2
int data[ARRAY_DATA_SIZE ] = 0;
int main() {
uint8_t currIdx = 0;
data[currIdx++] = 6;
data[currIdx++] = 19;
return 0;
}
I was told with small arrays it was better to use fixed macros, but I feel like it does not scale very well. What would be the general advice for this?
You should avoid macros whenever possible, and it's possible in this case. If you are using at least C++11 (and you should be), you can use constexpr to declare your magic constants at compile time:
static inline constexpr auto PREFIX_IDX = 0u;
static inline constexpr auto SUFFIX_IDX = 1u;
static inline constexpr auto ARRAY_DATA_SIZE = 2u;
That said, you need to match your code to the semantics of what you're doing. This makes your code more readable. The size of the array doesn't matter. What matters is if you've attached different meanings to different elements of the array.
You've attached a sematic tag of "prefix" to data[0] and one of "suffix" to data[1]. Since elements of the array have magic roles, you should index them with your magic constants.
int data[ARRAY_DATA_SIZE];
int main()
{
data[PREFIX_IDX] = 6;
data[SUFFIX_IDX] = 19;
return 0;
}
Depending on how complex your actual code is, it might be better to forego the array entirely and use separate variables. However, I've had code where you have to treat things as the same type of thing in one place and as different types in another, so an array is definitely OK.
Adding to what Spencer said (don't use #define):
Actually, it would be best to use an enumeration type. This idiom lets you have the benefits of named fields when you want to refer to a specific one, but also still lets you iterate over them if you want to process them all.
But, with a distinct enum type, you can wrap it in a class that implements operator[] and ensures that you use only those enumerations as subscripts, rather than arbitrary values.
Even if you don't do that, it serves to show that the names are related in a group, and it automatically increments them as you define them.
Also, int data[ARRAY_DATA_SIZE ] = 0; is confusing. You are initializing an array with an int, and the special value zero at that. This is not a pointer. A global array of ints will be zeroed anyway. So what is this for? Is it a mistake? Readers will wonder.
Of course, this could be an X-of-Y problem. If you are incrementing as with:
uint8_t currIdx = 0;
data[currIdx++] = 6;
data[currIdx++] = 19;
the right answer is to use an aggregate to do it all in one, not increment the subscript at all.
constexpr int vals[] = {6,19};
std::ranges::copy (vals, data.begin());
if you used std::array rather than the primitive array syntax, and you were always going to supply the whole thing, then you can just use a single normal assignment.
Let's say I have an alias for vector:
typedef std::vector<double> PlanetData;
And I want it's fields to be accessible via some keys:
double x = planet_data[PlanetDataKeys::PosX]; //planet_data is of type PlanetData
How can I achieve it?
I can define an enum inside a namespace:
namespace PlanetDataKeys {
enum {
PosX = 0,
PosY = 1
};
}
But enum class is safer:
enum class PlanetDataKeys {
PosX = 0,
PosY = 1
};
However, as implicit casting of enum class to int type is disabled, this would require to write:
double x = planet_data[static_cast<int>(PlanetDataKeys::PosX)];
which is a bit awkward .
Which approach is better in this case and why?
EDIT Some explanation for aliasing vector:
In real code, PlanetData have ~7 fields, maybe even more if I decide to expand it. And I'm creating an instance of it while parsing a string of form data_string = "date: 2903248.12343, position=[124543254.1343214,123213.12341,63456.1234], velocity=[...". That's why I wanted it to be a vector: to use something like planet_data.push_back(ParseNextDouble(data_string));
Please don't expect too much functionality from a humble vector.
Vector is not designed to access it's data with keys other than indices. Despite your examples are syntactically and semantically correct, they look like a misuse of std::vector and enum classes. Each tool has it's purpose, and vector seems to be not the best one for your task.
Enum classes were introduced to improve type safety. With them, you'll never mix up PlanetDataKeys, SatelliteEphemeris and KeplerianOrbitElements. But in your case you finally cast any of them to int, loosing all the conquest of type-safe enums.
As to me, it would be better to define a PlanetData class with a subscript operator which accepts PlanetDataKeys as it's argument.
If you want to stick with vectors, I'd choose the first variant (with namespaces). It's much easier to read and write, and I'm convinced that it's not even a little safer than enum classes used this way.
What about just defining scoped constants of the appropriate type, like so:
namespace PlanetDataKeys {
const size_t PosX = 0;
const size_t PosY = 1;
}
I was googling around how to iterate over enums, and I found a variety of suggestions, like
How can I iterate over an enum?
Although it is OK, that all those methods must lead back to iterating over integers, I find the suggested solutions more or less a kind of hacking. Is there any deeper reason why this operation is not better supported; or from the other side, which one is more portable (including one between C and C++) and more standard-proof?
To iterate over a generic enum, portably between C and C++, simply use look-up tables:
typedef enum
{
hello = 123,
world = 456
} hello_t;
const hello_t TABLE [ENUM_ITEMS] =
{
hello,
world
};
for(size_t i=0; i<ENUM_ITEMS; i++)
{
printf("%d", (int)TABLE[i]);
}
Unfortunately there is no way to programatically get the constant ENUM_ITEMS, unless you have a non-specific enum with no values assigned, like enum { hello, world, ENUM_ITEMS }. If some enumeration constants are explicitly assigned numbers, then you can only do something hack-ish like this:
typedef enum
{
ENUM_START = __LINE__,
hello = 123,
world = 456,
ENUM_ITEMS = __LINE__ - ENUM_START - 1
} hello_t;
C or C++ ? It's not the same thing.
You can't iterate over enum in C, because enum is just switched by there number at the compilation time.
however, if your sure of what's inside your enum, you can "iterate", like that :
enum color {
YELLOW,
GREEN,
BLUE,
RED,
/* Please, add new color BEFORE this comment */
NB_COLOR
};
for (int i = 0; i < NB_COLOR; ++i) {
/* Do something */
}
But it's more like a hack as you say it, because you can't be sure that your enum start with 0 and you can't be sure that there is not "empty slot" between enum in C.
I'm creating a Tetris clone in C++, and I have an enum GameProperty, which is specified as follows:
enum GameProperty {
NUM_OF_TETROMINOES = 7,
NUM_OF_TILES = 4,
TETROMINO_ROTATIONS = 4
};
In my case, I only use these values when looping through a tetromino's tiles, e.g:
for (int i = 0; i < TETROMINO_TILES; i++) { }
Is it under any circumstance considered bad practice to have multiple enumerators with the same value?
These should not be values in a single enum. They should be separate constants. To see why, look at code like i < TETROMINO_TILES. The compares an integer to a GameProperty which can have values like TETROMINO_ROTATIONS. That makes no sense.
Use enum when you want to create a new, distinct type which isn't really a scalar value. For example, colors can be enumerated, and hence numbered, but those numbers don't really mean anything.
If you're assigning meaningful numbers to the enumerators, it's a sign that you might really want something like this:
namespace GameProperty { // completely different concepts with unifying theme
int const num_tetrominoes = 7,
num_tiles = 4,
num_rotations = 4;
};
Now you can use the same syntax, as well as using declarations, and these constants work in for loops and expressions with no conversion.
For another example, the following are both correct but shouldn't be swapped between enum and int:
namespace wavelengths { // closely related quantities
typedef int wavelength_t; // maybe we will express in-between values
wavelength_t const red = 750,
green = 550,
blue = 400;
};
enum colors { // qualitatively different but related as one-of-many
red,
green,
blue;
};
Define a enum just like you define a class. It should conceptually be a collection of values for ONE property, instead of multiple properties rigged up.
I am having problems translating C++ data structures to Scala. Scala is really different from C++, but I like a lot of it.
I have the following Code fragment in C++:
struct Output
{
double point;
double solution[6];
};
struct Coeff
{
double rcont1[6];
double rcont2[6];
double rcont3[6];
double rcont4[6];
double rcont5[6];
double rcont6[6];
};
std::list<Output> output;
std::list<Coeff> coeff;
I now fill the list in a while loop with data
while(n<nmax) {
if step successfull
Output out;
out.point = some values;
out.solution[0] = some value;
output.push_back(out);
}
I tried creating a simple class in Scala to hold the data.
class Output
{
var point: Double
var solution: Array[Double] = new Array(6)
}
But this doens't work since point is not initialized. Is there a way around this? I just want to define the variable but not initialize it.
Another quick thing. I am looking for an equivalent to stl::lower_bound.
Is finds the right position to insert an element in an sorted container to maintain the order.
Thanks for helping a Scala beginner
Why don't you want to initialize it? For efficiency? I'm afraid that the JVM doesn't let you get away with having random junk in your variables based on whatever was there originally. So since you have to initialize it anyway, why not specify what your "uninitialized" value is?
class Output {
var point = 0.0
var solution = new Array[Double](6)
}
(You could use Double.NaN and check for point.isNaN if you later need to see whether the value has been initialized or not.)
You could use _ as the default initialization, but unless you use it in generic code:
class Holder[T] {
var held: T = _
}
then you're just obscuring what the value really will be set to. (Or you are announcing "I really don't care what goes here, it could be anything"--which could be useful.)
I just found the answer to the intialistion:
class Output
{
var point: Double = _
var solution: Array[Double] = Array(6)
}
Puh Scala has a lot of syntx to get used to :-)
Anyone have a solution for the lower_bound equivalent ?
It's hard to translate effectively, as you've left a lot of unknowns hidden behind pseudo code, but I'd advocate something along these lines:
// type alias
type Coeff = Seq[Seq[Double]]
// parameters passed to a case class become member fields
case class Output (point: Double, solution: Seq[Double])
val outputs = (0 to nmax) map { n =>
Output(generatePoint(n), generateSolution(n))
}
If you can flesh out your sample code a bit more fully, I'll be able to give a better translation.