Background
For a UI in an embedded project, I'm looking for a nice generic way to store a "state" and cycle through it with a button press, e.g. a list of menu items.
Normally, I like to use enums for this purpose, for example:
enum class MenuItem {
main,
config,
foo,
bar,
};
Then, in my UI code, I can store a currentMenuItem state like
MenuItem currentMenuItem = MenuItem::MAIN;
and do things depending on the current state by comparing currentMenuItem to any of its possible values, as declared in the enum.
Problem
The thing is, I would now like to advance to the next menu item. For that, I can quite trivially write a function that does that by casting to int, incrementing by one, and casting it back to the enum. I have multiple distinct enums, so I can even use this templated function that does this for arbitrary enums:
template <typename T>
void advanceEnum(T &e) {
e = static_cast<T>(static_cast<int>(e) + 1);
}
The problem with this is that it doesn't wrap around: it will happily keep increasing the underlying integer beyond the number of elements in the actual enum. I could quite easily solve this (by taking the modulo with the number of elements in the above function), if only there was an clean way to get the element count of an enum. Which, as far as I could find, there isn't really.
Custom enum?
I was thinking of writing a custom 'CyclicEnum' class that implements this behaviour, that I can subsequently derive from. That way, I could also write this as an overloaded operator++.
However, I still haven't devised how to can get an enum-like thing without actually using an enum. For example, I got to something like this:
class CyclicEnum {
public:
uint8_t v;
CyclicEnum& operator++() {
v = (v+1) % count;
return *this;
}
CyclicEnum operator++(int) {
CyclicEnum old = *this;
operator++();
return old;
}
private:
uint8_t count;
protected:
CyclicEnum(uint8_t v, uint8_t count) : v(v), count(count) {}
};
struct Tab : public CyclicEnum {
enum Value {
main,
config,
foo,
bar,
};
Tab(Value v) : CyclicEnum(v, 4) {}
};
However, as you can see, this still uses an enum inside the custom CyclicEnum class, and I'm back to the same issue: I can't count the number of Enum elements, so I have to specify that manually (which I think is not nice because it's redundant). Secondly, this way I also have to override the constructor in the derived class which I would like to avoid to keep it as clean as possible.
Upon searching this issue, many people apparently recommend to add a "dummy" value at the end of the enum as a trick to get the size:
enum Value {
main,
config,
foo,
bar,
_count,
};
but frankly, I find that just ugly, since _count is now actually a valid option.
Is there any way around this? Am I abusing enums? Looking at the fact that enums are apparently (by design) so hard to count, probably. But what would be a nice way to have a structure like this with named values like an enum provides?
EDIT:
OK, I'm convinced that using a _count element at the end isn't so bad of an idea. Still, I'd like to encapsulate this in some kind of structure, like a class.
I also thought of instead of using inheritance, using a class template to accomplish this, something like this:
(caution, this doesn't compile):
template<typename T>
struct CyclicEnum {
T v;
enum Values = T;
CyclicEnum& operator++() {
v = (v+1) % T::_count;
return *this;
}
CyclicEnum operator++(int) {
CyclicEnum old = *this;
operator++();
return old;
}
CyclicEnum(T v) : v(v) {}
};
struct MenuItem : public CyclicEnum<enum class {
main,
config,
foo,
bar,
_count,
}> {};
However, this does not work because "ISO C++ forbids forward references to 'enum' types" and "anonymous enum cannot be defined in a type specifier"...
Is there another way to make this idea work (template a class with an enum), or is this not going to work?
The thing is, I would now like to advance to the next menu item.
++ comes to mind. Keep it simple.
That way, I could also write this as an overloaded operator++
Yeah... or again, keep it simple, you could just drop the whole class. There's no need to write an abstraction layer around a simple integer. Really.
Upon searching this issue, many people apparently recommend to add a "dummy" value at the end of the enum as a trick to get the size
Sure why not. This is incredibly common practice.
but frankly, I find that just ugly, since LAST is now actually a valid option.
It's canonical code, it isn't ugly. Just give it a sensible name, maybe something like MENU_ITEMS_N to suggest that this a counter variable then use it as such. for(int i=0; i<MENU_ITEMS_N; i++) ...
Am I abusing enums?
Enums are just named integer values. Don't over-engineer your code. It's bad for performance, it's bad for maintenance, it adds needless complexity.
You could use the magic_enum library to reflect on enums.
Example which gets the names of all enum elements as std::array < std::string_view > and prints them.
#include <algorithm>
#include <iostream>
#include <magic_enum.hpp>
enum struct Apple
{
Fuji = 2,
Honeycrisp = -3,
Envy = 4
};
int
main ()
{
constexpr auto &appleNames = magic_enum::enum_names<Apple> (); // get an std::array<std::string_view> with the names for the enum sorted by value
std::copy (appleNames.begin (), appleNames.end (), std::ostream_iterator<std::string_view> (std::cout, "\n")); // print all the names
}
Prints:
Honeycrisp
Fuji
Envy
There are some limitations please read magic enum limitations
Rather then using _count, set the last "sentinel" value to the last actual value.
enum Value {
main,
config,
foo,
bar,
last = bar
};
Then you avoid the problem of having an enum value that is not a valid menu option. in your increment for example instead of :
v = static_cast<Value>( (static_cast<int>(v) + 1) %
static_cast<int>(Value::_count) );
you'd have:
v = static_cast<Value>( (static_cast<int>(v) + 1) %
(static_cast<int>(Value::last) + 1) ) ;
If in fact these enums simply cause different menu item handler functions to be called, then you could instead used an array of pointer-to-functions rather then an enum/switch or whatever.
Related
I am trying to design a data stuctures, which would enhance/supplement an existing one by storing some additional data about it's members.
Let's say we have:
class A {
int x;
string y;
};
And we want to have a GUI component associated with it, so the data members have corresponding GUI elements. I'd like to map the members to their respective components. Something like
class GuiA {
int x;
string y;
map<MemberHandle, GuiElement*> guiHandles;
}
I don't have any restrictions, but I'd like the result to be easily convertible to the original type.
I am aware, that I could introduce a template e.g. GuiElementMember holding original data plus the GuiElement pointer, and swap class member for their decorated counterparts, so it would look like:
class GuiA {
GuiElementMember<int> x;
GuiElementMember<string> y;
}
but I'd like to avoid it, as it completely changes access patterns to data members and bloats it. I.e. it results with data members interleaved with pointers, that are not easy to strip out.
Ideally it would be possible to write GuiA as a derived class of A, or as a composition of A and something additional.
I was thinking about something like a template that class could produce the map. I could yield to write a custom class per component, but I don't think there is an easy way to map data members, so on the clients side it would look like getGuiMember(GuiA::x). The pointer to data member contains the member original type. I don't think it is possible to have something like "type-erased pointer to member" that could serve as a MemberHandle type.
The only thing that comes to my mind is a custom enum per component which would enumerate data members and serve as key type for a map (or a vector in this case), but it seems as an awful lot of information duplication and maintenance.
Is there some technique that allows mapping data members?
I don't really care about the implementational complexity as long as the interface is easy. I welcome boost or template magic. I also don't care about the performance of additional data access, it's extra stuff, but the plain class usage should not be impacted, so introduction of indirection that cannot be optimized is less welcomed.
EDIT: Please don't hinge on GUI thing it's an example. I am only concerned about storing some additional data per member without composing it with the member.
You can use BOOST_FUSION_DEFINE_STRUCT to define your structures that can be iterated over with a for_each loop:
#include <boost/fusion/include/define_struct.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <unordered_map>
#include <string>
#include <cstdint>
BOOST_FUSION_DEFINE_STRUCT(
(demo), employee,
(std::string, name)
(int, age)
)
struct GuiElement;
GuiElement* createGuiElement(char const* name);
using Mapping = std::unordered_map<size_t, GuiElement*>;
template<class T>
Mapping create_mapping(T&& t) {
Mapping mapping;
boost::fusion::for_each(t, [&](auto& member) {
auto offset = reinterpret_cast<uintptr_t>(&member) - reinterpret_cast<uintptr_t>(&t);
mapping[offset];
});
return mapping;
}
template<class T, class M>
GuiElement*& get_mapping_element(Mapping& mapping, T const& t, M const& member) {
auto offset = reinterpret_cast<uintptr_t>(&member) - reinterpret_cast<uintptr_t>(&t);
auto found = mapping.find(offset);
if(found == mapping.end())
std::abort();
return found->second;
}
int main() {
auto employee_mapping = create_mapping(demo::employee{});
demo::employee e1;
get_mapping_element(employee_mapping, e1, e1.name) = createGuiElement("name");
get_mapping_element(employee_mapping, e1, e1.age) = createGuiElement("age");
}
In the code there is a Mapping, one per class. Each member is identified by its offset from the beginning of its enclosing class.
In general, you use macros for such purposes. They can generate any kind of code/wrappers that you'd like, letting you have the usual access to your data, but also adding stuff you want/need. It ain't pretty, but it works.
There are some template libraries that can help here, like Boost.Fusion or Boost.Hana, but, you can also roll your own here if you don't have a use for their advanced features (which come with the long compilation price tag).
Also, if you can focus on a particular GUI framework, they have some support for such things. For example, Qt has its own "meta object" compiler.
You could try a template for this?
e.g.
template <typename T>
class GuiItem : public T {
map<MemberHandle, GuiElement*> guiHandles;
}
GuiItem<A> guiA;
guiA.x = 123;
guiA.y = "y";
guiA.guiHandles[handle] = element;
I'm not sure I understand the other requirements so this way may not work for you.
I have 2 issues in a template class I'm building. I've included example code below. First question is whether I can coerce the auto type deducted for a templated class. i.e.:
auto p = myvar;
where myvar is T<...>, could I force auto to detect Q<...>? This is simplified. Read on for a more clear explanation.
Edited for clarity: Let me explain what I'm doing. And I'd also like to indicate that this style code is working on a large-scale project perfectly well. I am trying to add some features and functions and in addition to smooth out some of the more awkward behaviors.
The code uses templates to perform work on n-dimensional arrays. The template has a top-level class, and a storage class underneath. Passing the storage class into the top level class allows for a top level class which inherits the storage class. So I start with NDimVar, and I have NDimStor. I end up with
NDimVar<NDimStor>
The class contains NO DATA except for the buffer of data:
class NDimStor<size_t... dimensions> {
int buffer[Size<dimensions...>()]
}
This makes the address of the class == the address of the buffer. This is key to the whole implementation. Is this an incorrect assumption? (I can see this works on my system without any issues, but perhaps this isn't always the case.)
When I create NDimVar<NDimStor<10,10>> I end up with a 10x10 array.
I have functions for getting pieces of the array, for example:
NDimVar<NDimStor<dimensions...>>::RemoveDim & get(int index);
This creates a new 1d array of 10 elements out of the 2d 10x10 array:
NDimVar<NdimStor<10>>
In order to return this as a reference, I use a reinterpret_cast at the location of the data I want. So in this example, get(3) would perform:
return reinterpret_cast<NDimVar≤NDimStor<dimensions...>>::RemoveDim&>(buffer[index * DimensionSumBelow<0>()]);
DimensionSumBelow<0> returns the sum of elements at dimensions 1+, i.e. 10. So &buffer[30] is the address of the referenced 1d NDimVar.
All of this works very well.
The only issue I have is that I would like to add on overlays. For example, be able to return a reference to a new class:
NDimVar<NDimPermute<NDimStor<10,10>,1,0>>
that points to the same original location along with a permutation behavior (swapping dimensions). This also works well. But I would like for:
auto p = myvar.Permute<1,0>()
to create a new copy of myvar with permuted data. This would work if I said:
NDimVar<NDimStor<10,10>> p = myvar.Permute<1,0>().
I feel that there is some auto type deduction stuff I could do in order to coerce the auto type returned, but I'm not sure. I haven't been able to figure it out.
Thanks again,
Nachum
What I want is:
1. Create temporary overlay classes on my storage, e.g. A_top<A_storage> can return a type called A_top<A_overlay<A_storage>> without creating a new object, it just returns a reference to this type. This changes the way the storage is accessed. The problem is upon a call to auto. I don't want this type to be instantiated directly. Can I modify the return to auto to be an original A_top?
#include <iostream>
using namespace std;
class A_storage {
public:
float arr[10];
A_storage () {
}
float & el (int index) {
return arr[index];
}
};
template <typename T> class A_overlay : T {
private:
A_overlay () {
cout << "A_overlay ()" << endl;
}
A_overlay (const A_overlay &) {
cout << "A_overlay (&)" << endl;
}
public:
using T::arr;
float & el (int index) {
return arr[10 - index];
}
};
template <typename T> class A_top;
template <typename T> class A_top : public T {
public:
A_top () {
}
A_top<A_overlay<A_storage>> & get () {
return reinterpret_cast<A_top<A_overlay<A_storage>>&>(*this);
}
};
using A = A_top<A_storage>;
int main (void) {
A a;
auto c = a.get(); // illegal - can i auto type deduce to A_top<A_storage>?
return 0;
}
If a function accepts (A_top<A_storage> &) as a parameter, how can I create a conversion function that can cast A_top<A_overlay<A_storage>>& to A_top<A_storage>& ?
Thanks,
Nachum
First, your design doesn't look right to me, and I'm not sure if the behaviour is actually well-defined or not. (Probably not.)
In any case, the problem is not with auto. The error is caused by the fact that the copy constructor of A_overlay is private, while you need it to copy A_top<A_overlay<A_storage>> returned by a.get() to auto c.
(Note that the auto in this case obviously gets deduced to A_top<A_overlay<A_storage>>, I assume you made a typo when said that it's A_top<A_storage>.)
Also note that A_storage in A_top::get() should be replaced with T, even if it doesn't change anything in your snippet because you only have T == A_storage.
If a function accepts (A_top &) as a parameter, how can I create a conversion function that can cast A_top> to A_top& ?
Ehm, isn't it just this:
return reinterpret_cast<A_top<A_storage>&>(obj);
reinterpret_cast should almost never be used. It essentially remove any compiler validation that the types are related. And doing unrelated cast is essentially undefined behavior as it essentially assume that derived classes are always at offset 0...
It does not make any sense to write such code. It is not maintainable and hard to understand what you are trying to achieve. It look like you want to pretend that your A_top<A_storage> object is a A_top<A_overlay<A_storage>> object instead. If this is what you want to do, then declare A alias as that type.
In your code, it look like you want to invert the indexing so that item at position 10 is returned when you ask item at position 0 and vice versa. Do you really think, that it is obvious from your obfuscated code? Never write such bad code.
Something like
class A_overlay {
public:
float & el (int index) { return arr[10 - index]; }
private:
A_storage arr;
};
would make much more sense than your current code.
No cast needed.
Easy to understand.
Well defined behavior.
You might keep your job.
And obviously, you would update the following line as appropriate:
using A = A_top<A_storage>;
Also, if A_top has no useful purpose, then why not using A_overlay directly? And why are you using template if A_storage is not a template? Do you really want to reuse such mess elsewhere in your code base.
Obviously, your code inheritance does not respect IS-A relationship if your write such code. So it is clearly a bad design!
Iterator of each datastructure has different type of return value of operator*() e.g. :-
Most array-like DataStructure<T> : return T&.
std::unordered_map<K,T> : return std::pair<const K, T>&.
const std::unordered_map<K,T> : return const std::pair<K, T>&.
What should be the datatype if my iterator::operator*() want to return something more complex (std::pair is not enough)?
Example
I have a custom 3D datastructure Map3D<T> that is like a map (int,int,int)->T.
To achieve the above requirement, I create a new class Bundle3D<T>.
template<class T>class Bundle3D {
//getInternalIndex1D()
//getCoordinate()
//getValue()
};
The Map3D<T>'s iterator::operator* would have signature like :-
Bundle3D<T> iterator::operator*(){ ... }
Its usage is like :-
Map3D<float> map;
for(auto& ele:map){ //"ele" has some special type named "Bundle"
int keyInternal1DIndex=ele.getInternalIndex1D();
Vector3Int& key=ele.getCoordinate();
float& value=ele.getValue();
}
It works good, but I think my code is not standardized.
In other words, Bundle3D<T>, getInternalIndex1D(), getCoordinate() and getValue() is blindly named by me.
In real case, I have created a lot of custom data-structures that generate such strange iterator.
Question
Is there any std::/standard type of return-value of iterator::operator*(), when T& and std::pair is not enough?
I have doubted about this for several months, but feel very reluctant to ask it.
If this question need improvement, please comment.
Edit
(clarify the word standardized - this part is my subjective notion.)
I feel that all types of standard collection in most language, e.g. :-
java.util.Collection/ArrayList in Java
std::unordered_map/vector in C++
Iterators of all of them have signatures of function getValue() or operator* that return either T or StandardPair<index,T> - no other types.
For many years, I am convinced that it is a rule or a strong convention/tradition that I really should obey.
There must be a reason.
However, I am not sure what it is, because I am probably very new to C++.
If I design my software to return something strange (e.g. Bundle3D<T> in the above example), I think I will get punished hard from the unconventional design. (e.g. not have .first field)
What you have right now is okay. I would just specify one thing that I think isn't very C++-ish and may in fact harm your standardization options in the future.
It's the getters. Obviously you have deep roots in Java, and the concept of public members is abhorred in Java programming, so much so that the concept of "beans" exists. I don't intend to knock on Java here, it's a nice language with its own nice idioms.
But this is C++, with it's own programming idioms. You obviously noticed the direct access to the contents of std::pair. It's like that for a reason. A pair is just two items packed together, that's the sum of its behavior. Getters would just ,well, get in the way. :)
There's no need for them, because we aren't dealing with an "abstraction" of two items bundled together, but instead we really do have a concrete, honest to god, bundle1.
Obviously we can have bundles of more than two items. That's why we have std::tuple. Now while it's true that all access to a tuple is through a non-member function called get, that's simply because there is no way to give names to members of an arbitrarily sized bundle. get still returns a reference to the element, so you retain direct access into the bundle.
This long winded exposition is important, because an upcoming C++1z feature, called "Structured Bindings", relies on the standard behavior of tuples and pairs, as well as how C++ programmers see aggregates. Under this feature, an iteration over a map, will look like this:
#include <map>
#include <iostream>
std::map<char const*, int> foo()
{
return {
{ "foo", 3 },
{ "bar", 7 },
{ "baz", 1 },
};
}
int main() {
for (auto [key, val] : foo()) {
std:: cout << "( " << key << ", " << val << " )\n";
}
return 0;
}
Live example
And the same extends to any user defined bundle of data. Your own return value type in the post can be bound similarly, if the members are public:
struct Vector3Int {};
template<class T>
struct Bundle3D {
int internal_index_id;
Vector3Int const &coord;
T &value;
};
int main() {
Vector3Int vec;
float val;
Bundle3D<float> bundle{ 1, vec, val };
auto[ idx_id, coord, value] = bundle;
// coord = {}; // compile error since coord gets the cv qualifer
}
Live example
So my suggestion is, leave the getters to your Java code, and use aggregates as bundles of data for C++.
1 An aggregate, to be more formal.
I'm going to assume that your Map3D is a spacial co-ordinate to value container.
I would return a std::pair<const Vector3Int, T>&, and not bother with getInternalIndex1D as part of the return. That can be left as a function Vector3Int -> int.
Have a look at UnorderedAssociativeContainer for the sorts of members that would be useful to define
e.g.
template <typename T>
class Map3D
{
using key_type = Vector3Int;
using mapped_type = T;
using value_type = Bundle3D<T>; // Key, Value, Internal1DIndex
using reference = Bundle3D<T> &;
using pointer = Bundle3D<T> *;
using hasher = /*Function object that calculates Internal1DIndex*/
using key_equal = std::equal<Vector3Int>
... iterators, const_* definitions, etc
}
I've got way too much information to work with, so for now I'll consider this question answered until I can sort it all out and decide on the final implementation! Thanks a ton gf and Simon Buchan. I wish I could accept both of your answers, since they're both definite possibilities!
Additional / Revised Conceptual Information as suggested:
What I am aiming to do;
I am making a game. In this game every object used is an instance of the DOBJ class. The TUR class extends the DOBJ class. The SHO class extends the TUR class.
Each TUR class has an array of SHO's stored in it's SHOARR array. Each SHO instance needs to be given a set of instructions.
I know for a fact I could make 1000's of different SHO classes that have their instructions set during construction.
However, considering I will have so many different acting SHO instances, I was interested in another way to pass a set of instructions. Through the contruction of the SHO would be the ideal.
The instructions I am attempting to pass to each SHO are simple if statements;
if(frame > 64) { rotation += 4; };
if(state == 0 && frame < 32) { xs = 12; ys = 12; state = 1; };
Original question
Migration from ActionScript3.0 to C++ is proving to be a trial indeed. Thanks to those who have answered my questions thus far and also to those who opened stackoverflow in the first place. Onto the question... (TL;DR near the bottom to get straight to the question)
I'm attempting to apply the same logic that I could apply in AS3.0 to my project in C++ and it's just not going very well.
In AS3.0 I was used to slapping any and every datatype into an Array. It made things pretty simple. Now that I've run into C++ dev, I realized that I can't exactly do that anymore.
So now I'm stuck with this problem of rewriting a little AI system in a new language, where the driving point of the system isn't even compatible!
Here's an example of a piece of the code I was writing in AS3.0;
AI[NUM][1]( OBJ, AI[NUM][2], AI[NUM][3] );
AI being an array, NUM being an integer, OBJ being an instance of a class.
This line obviously called the function in the second element of the first array in the main array with the arguments being a class in which to perform the function on, whatever was in the third element of the first array of the main array, and likewise the fourth element.
In this case;
AI[NUM][1] would be a function
AI[NUM][2] would be a variable
AI[NUM][3] would be a number
Generally, my AI was run on calling a function to change or compare the variable with a number.
An example would be;
CompareST( someObject, "x", 500 );
and return true if someObject's x variable was smaller than (ST) 500.
The AI array itself was just filled with arrays of calls similar to this.
Quite new to C++ I had no idea how to go about this, so I did a bit of searching and reading of many different websites and came to the conclusion that I should look into function pointers.
However, after reading a bit into them, I've come to the conclusion that it won't help me realize my goal. While it did help me call functions like I wanted to call them, it doesn't help me stack different datatypes into one large array of arrays.
TL;DR
EDIT++:
What I need for each object is a set of instructions to be checked every frame. However, for each instance of the class, the instructions have to be different.
I plan on having a LOT of different instances, so making a class for each one is unreasonable.
Thus, I needed a way to pass a set of instructions to each one through it's constructor and read + execute them at any time their think() function is called.
My ultimate goal (aside from finding out about a better way to go about this) would be to be able to have an array of function calls, like;
A[n][0]( O, A[n][1], A[n][2] );
Where;
O is the instance the function is altering
A[n][0] is a function (Equality or Comparison)
A[n][1] is the variable, eg; "x", O["x"] (or a pointer to that variable in the case of C++)
A[n][2] is the value to alter the variable by, or compare it to.
And I'm not sure how I would rewrite this into C++, or alter it to work in another way.
Aftermath / Additional Information
What I'm actually aiming to do is be able to give an object a set of instructions at the time of it's creation, through the constructor. For example upon creation give an object instructions to wait 64 frames, and then rotate in the opposite direction, would have been something like this;
t.AI = [ [ 1, AIF.CompareET, "STATE", 0, AIF.CompareGT, "FRAME", 64, 0, AIF.EqualityAT, "baseRotation", 180, AIF.EqualityET, "STATE", 1 ] ];
In pseudocode;
(The 1 in the array denotes how to read the rest of the array, in this case everything before the odd 0 [ The one that comes after 64 ] is a comparison. If any of those fail, anything after the 0 will not be looked at )
Compare STATE is equal to (ET) 0, if true
Compare FRAME is greather than (GT) 64, if true
Add 180 to (AT) baseRotation, Set STATE equal to 1
Sorry that this turned out really long. I hope it's understandable, and I'm not asking something stupidly difficult to explain.
You can store functions using function pointers or functors. Variant types though are not natively supported by C++, you have to use custom solutions there.
One possibility would be to use Boost.Any (or better, Boost.Variant if you only use a fixed set of types):
typedef void (*Function)(Object*, const std::string&, boost::any&);
std::vector<Function> functions;
Given some function:
void f(Object* obj, const std::string& name, boost::any& value) {
// ...
}
you could store and call it similar to your example:
functions.push_back(&f);
functions[0](obj, "x", boost::any(500));
To utilize a declarative syntax, there are three options that come to my mind:
you use a similar approach and have central "interpreter" function, e.g. based on a switch (don't forget to switch to integers or pointers-to-members instead of strings if you need performance)
you invent your own language and generate C++ code from description files
you compose function objects in a declarative way
To do composition, you could use Boost.Bind or something like custom objects that represent operations:
struct Operation {
virtual ~Operation() {}
virtual bool operator()(Object&) = 0;
};
template<class T>
struct GreaterThen : Operation {
typedef T Object::*Member;
Member member;
const T value;
CompareGT(Member member, const T& value) : member(member), value(value) {}
bool operator()(Object& obj) { return (obj.*member > value); }
};
template<class T>
struct SetTo : Operation {
typedef T Object::*member;
Member member;
const T value;
SetTo(Member member, const T& value) : member(member), value(value) {}
bool operator()(Object& obj) { obj.*member = value; return true; }
};
Now we can build operation lists:
typedef std::vector<Operation*> OpList;
OpList operation;
operations.push_back(new GreaterThen<int>(&Object::Frame, 64));
operations.push_back(new SetTo<int>(&Object::State, 1));
We can use helper functions to avoid having to specify the template types:
template<class T>
Operation* opGreaterThen(T Object::*mem, const T& val) {
return new GreaterThen<T>(mem, val);
}
Assuming a similar helper for SetTo and using Boost.Assign the above becomes:
OpList operations = boost::assign::list_of
(opGreaterThen(&Object::Frame, 64))
(opSetTo (&Object::State, 1));
Executing the operations becomes the following then:
OpList::iterator it = operation.begin();
for( ; it != operations.end(); ++it) {
Operation& op = *it; // just for readability
if(!op(someObject)) break; // stop if operation returns false
}
Wow.
Reading through that slowly suggests what you're trying to end up with is an array of function calls and you can choose a different function with the same parameters (but different implementation) for different actions and choose the correct one for the correct case.
If that is the case, you're looking for function pointers. Try this tutorial.
You should be able to use a function pointer with an argument set and point it to the correct function based on your needs. You won't need an array of function pointers for this either - any function that matches the definition should do. From the tutorial, declare a function pointer like this:
int (TMyClass::*functptr)(classname, int, int) = NULL; // C++
Then assign it later:
this.functptr = &TMyClass::doitthisway;
While it is possible (although a pain) to have an array of arbitrary types, you pretty much never need it, since you have to know something about what is where to do anything interesting with it: for example, your 'TL;DR' example seems to look something like:
struct AIRule {
// Can only handle comparing ints, see later for more general solution.
typedef bool compare_type(AIObject*, AIObject::*int, int);
compare_type* compare;
AIObject* object;
AIObject::int* member;
int comparand;
};
So now you can do something like:
bool ai_equal(AIObject* object, AIObject::int* member, int comparand) {
return object->*member == comparand;
}
...
ai[n].compare = &ai_equal;
ai[n].object = some_object;
ai[n].member = &AIObject::some_member;
ai[n].comparand = 50;
...
if (ai[n].compare(ai[n].object, ai[n].member, ai[n].comparand)) {
...
}
This just moves the any type problem from the rules array to member though. C++ needs to know at least how many bytes a member is, and a string (for example) can be much bigger than an int. You can get around this by using pointers: which essentially is C++'s version of any, but you then need to delete it yourself (or you will leak memory!), at which point the interface method below becomes simpler.
If I was doing what you seem to want, I would use inheritance:
struct Sprite {
int frame;
double rotation;
Sprite() {
frame = 0;
rotation = 0.0;
}
virtual ~Sprite() {}
virtual void think() {
++frame;
}
virtual void draw() {
...
}
};
struct RotatingSprite : public Sprite {
int state;
MyShape() {
state = 0;
}
void think() {
Sprite::think();
if (state == 0 && frame > 64) {
state = 1;
rotation += 180.0;
}
}
};
Or a function pointer:
struct Sprite {
int frame;
double rotation;
void (*think)(Sprite*);
Sprite() {
frame = 0;
rotation = 0.0;
}
};
void rotate_think(Sprite* sprite) {
if (sprite->state == 0 && sprite->frame > 64) {
sprite->state = 1;
sprite->rotation += 180.0;
}
}
...
sprite->think = &rotate_think;
If you really need to do it dynamically I would recommend using the ++ part of C++. For the predicates (a predicate is just something that returns a boolean, like isLowerCase()) create an AIPredicate interface, and the actions an AIAction interface:
struct AIPredicate {
// "When you delete an AIPredicate, delete the full type, not just this interface."
virtual ~AIPredicate() {}
// "You can treat this as a function (operator()) but I'm not providing an implementation here ( = 0)"
virtual bool operator()(AIObject* object) = 0;
};
struct AIAction {
virtual ~AIAction() {}
virtual void operator()(AIObject* object) = 0;
};
struct AIRule {
// std::auto_ptr (or std::unique_ptr if you can use C++0x) will delete predicate for you.
// Add "#include <memory>" to your includes if it complains (most std headers will include it already)
std::auto_ptr<AIPredicate> predicate;
std::auto_ptr<AIAction> action;
};
Now you can make types like:
struct AIFrame : public AIPredicate {
// Implement the operator() member AICondition promises.
bool operator()(AIObject* object) {
return object->foo < 100;
}
};
...
// Use .reset() instead of = if you use std::unique_ptr.
ai[n].predicate = new AIFooIsLow();
If you want to have a very general predicate type, you can use the very powerful (and complicated) templates feature:
// The naming convention I'm using here is 'T'TitleCase for template parameters, TitleCase for types,
// lower_case for arguments and variables and '_'lower_case for members.
template<typename TMemberType, AIObject::TMemberType* TMember>
struct AIMemberEquals : public AIPredicate {
// Constructor: Initializes a new instance after it is created.
AIMemberEquals(TMemberType comparand) {
// Save comparand argument so we can use it in operator().
_comparand = comparand;
}
bool operator()(AIObject* object) {
return object->*TMember == comparand;
}
// Stores the value to compare.
TMemberType _comparand;
};
Unfortunately, creating templates looks a bit crazy:
ai[n].predicate = new AIMemberEquals<int, &AIObject::some_member>(100);
Read it as "create a new instance of (the type that AIMemberEquals applied to int and (the some_member member of AIObject) creates), with the argument 100".
When you have multiple predicates memory management becomes a bit more difficult without C++0x's unique_ptr or shared_ptr, types that will delete the object for you, since std::auto_ptr doesn't work in containers:
#include <vector>
struct AIData {
// vector is fairly close to AS3's Array type, it is a good default for
// arrays of changing or unknown size.
std::vector<AIPredicate*> predicates;
// Destructor: will be run before the memory for this object is freed.
~AIData() {
for (int i = 0; i != predicates.size(); ++i) {
delete predicates[i];
}
}
};
...
ai[n].predicates.push_back(new AIFooIsLow());
...
for (int i = 0; i != ai[n].predicates.size(); ++i) {
(*ai[n].predicates[i])(ai[n].object);
}
In C++0x:
struct AIData {
// unique_ptr will delete it for you, so no ~AIData() needed.
std::vector<unique_ptr<AIPredicate>> predicates;
};
Your final example could in C++ look something like:
std::auto_ptr<Shape> shape(new Shape());
...
std::auto_ptr<AIRule> rule(new AIRule());
rule->predicates.push(new AIMemberEquals<int, &Shape::state>(0));
rule->predicates.push(new AIMemberGreater<int, &Shape::frame>(64));
rule->actions.push(new AIAddMember<double, &Shape::rotation>(180.0));
rule->actions.push(new AISetMember<int, &Shape::state>(1));
shape->ai.push(rule); // .push(std::move(rule)); if you are using unique_ptr
Certainly not as pretty, but it works and is fairly flexible.
The problem:
I have a C++ class with gajillion (>100) members that behave nearly identically:
same type
in a function, each member has the same exact code done to it as other members, e.g. assignment from a map in a constructor where map key is same as member key
This identicality of behavior is repeated across many-many functions (>20), of course the behavior in each function is different so there's no way to factor things out.
The list of members is very fluid, with constant additions and sometimes deletions, some (but not all) driven by changing columns in a DB table.
As you can imagine, this presents a big pain-in-the-behind as far as code creation and maintenance, since to add a new member you have to add code to every function
where analogous members are used.
Example of a solution I'd like
Actual C++ code I need (say, in constructor):
MyClass::MyClass(SomeMap & map) { // construct an object from a map
intMember1 = map["intMember1"];
intMember2 = map["intMember2"];
... // Up to
intMemberN = map["intMemberN"];
}
C++ code I want to be able to write:
MyClass::MyClass(SomeMap & map) { // construct an object from a map
#FOR_EACH_WORD Label ("intMember1", "intMember2", ... "intMemberN")
$Label = map["$Label"];
#END_FOR_EACH_WORD
}
Requirements
The solution must be compatible with GCC (with Nmake as make system, if that matters).
Don't care about other compilers.
The solution can be on a pre-processor level, or something compilable. I'm fine with either one; but so far, all of my research pointed me to the conclusion that the latter is just plain out impossible in C++ (I so miss Perl now that I'm forced to do C++ !)
The solution must be to at least some extent "industry standard" (e.g. Boost is great, but a custom Perl script that Joe-Quick-Fingers created once and posted on his blog is not. Heck, I can easily write that Perl script, being much more of a Perl expert than a C++ one - I just can't get bigwigs in Software Engineering at my BigCompany to buy into using it :) )
The solution should allow me to declare a list of IDs (ideally, in only one header file instead of in every "#FOR_EACH_WORD" directive as I did in the example above)
The solution must not be limited to "create an object from a DB table" constructor. There are many functions, most of them not constructors, that need this.
A solution of "Make them all values in a single vector, and then run a 'for' loop across the vector" is an obvious one, and can not be used - the code's in a library used by many apps, the members are public, and re-writing those apps to use vector members instead of named members is out of the question, sadly.
Boost includes a great preprocessor library that you can use to generate such code:
#include <boost/preprocessor/repetition.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/cat.hpp>
typedef std::map<std::string, int> SomeMap;
class MyClass
{
public:
int intMember1, intMember2, intMember3;
MyClass(SomeMap & map)
{
#define ASSIGN(z,n,_) BOOST_PP_CAT(intMember, n) = map[ BOOST_PP_STRINGIZE(BOOST_PP_CAT(intMember, n))];
BOOST_PP_REPEAT_FROM_TO(1, 4, ASSIGN, nil)
}
};
Boost.Preprocessor proposes many convenient macros to perform such operations. Bojan Resnik already provided a solution using this library, but it assumes that every member name is constructed the same way.
Since you explicitely required the possibily to declare a list of IDs, here is a solution that should better fulfill your needs.
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/stringize.hpp>
// sequence of member names (can be declared in a separate header file)
#define MEMBERS (foo)(bar)
// macro for the map example
#define GET_FROM_MAP(r, map, member) member = map[BOOST_PP_STRINGIZE(member)];
BOOST_PP_SEQ_FOR_EACH(GET_FROM_MAP, mymap, MEMBERS)
// generates
// foo = mymap["foo"]; bar = mymap["bar];
-------
//Somewhere else, we need to print all the values on the standard output:
#define PRINT(r, ostream, member) ostream << member << std::endl;
BOOST_PP_SEQ_FOR_EACH(PRINT, std::cout, MEMBERS)
As you can see, you just need to write a macro representing the pattern you want to repeat, and pass it to the BOOST_PP_SEQ_FOR_EACH macro.
You could do something like this: create an adapter class or modify the existing class to have a vector of pointers to those fields, add the addresses of all member variables in question to that vector in the class constructor, then when needed run the for-loop on that vector. This way you don't (or almost don't) change the class for external users and have a nice for-loop capability.
Of course, the obvious question is: Why do you have a class with 100 members? It doesn't really seem sane.
Assuming it is sane nevertheless -- have you looked at boost preprocessor library? I have never used it myself (as one friend used to say: doing so leads to the dark side), but from what I heard it should be the tool for the job.
Surreptitiously use perl on your own machine to create the constructor. Then ask to increase your salary since you're succesfully maintaining such a huge chunk of code.
You could use the preprocessor to define the members, and later use the same definition to access them:
#define MEMBERS\
MEMBER( int, value )\
SEP MEMBER( double, value2 )\
SEP MEMBER( std::string, value3 )\
struct FluctuatingMembers {
#define SEP ;
#define MEMBER( type, name ) type name
MEMBERS
#undef MEMBER
#undef SEP
};
.. client code:
FluctuatingMembers f = { 1,2., "valuesofstringtype" };
std::cout <<
#define SEP <<
#define MEMBER( type, name ) #name << ":" << f.##name
MEMBERS;
#undef MEMBER
#undef SEP
It worked for me, but is hard to debug.
You can also implement a visitor pattern based on pointer-to-members. After the preprocessor solution, this one turns out way more debuggeable.
struct FluctuatingMembers {
int v1;
double v2;
std::string v3;
template<typename Visitor> static void each_member( Visitor& v );
};
template<typename Visitor> void FluctuatingMembers::each_member( Visitor& v ) {
v.accept( &FluctuatingMembers::v1 );
v.accept( &FluctuatingMembers::v2 );
v.accept( &FluctuatingMembers::v3 );
}
struct Printer {
FluctuatingMembers& f;
template< typename pt_member > void accept( pt_member m ) const {
std::cout << (f::*m) << "\n";
}
};
// you can even use this approach for visiting
// multiple objects simultaneously
struct MemberComparer {
FluctuatingMembers& f1, &f2;
bool different;
MemberComparer( FluctuatingMembers& f1, FluctuatingMembers& f2 )
: f1(f1),f2(f2)
,different(false)
{}
template< typename pt_member > void accept( pt_member m ) {
if( (f1::*m) != (f2::*m) ) different = true;
}
};
... client code:
FluctuatingMembers object1 = { 1, 2.2, "value2" }
, object2 = { 1, 2.2, "valuetoo" };
Comparer compare( object1, object2 );
FluctuatingMembers::each_member( compare );
Printer pr = { object1 };
FluctuatingMembers::each_member( pr );
Why not do it at run time? (I really hate macro hackery)
What you really are asking for, in some sense, is class metadata.
So I would try something like:
class AMember{
......
};
class YourClass{
AMember member1;
AMember member2;
....
AMember memberN;
typedef AMember YourClass::* pMember_t;
struct MetaData : public std::vector<std::pair<std::string,pMember_t>>{
MetaData(){
push_back(std::make_pair(std::string("member1"),&YourClass::member1));
...
push_back(std::make_pair(std::string("memberN"),&YourClass::memberN));
}
};
static const MetaData& myMetaData() {
static const MetaData m;//initialized once
return m;
}
YourClass(const std::map<std::string,AMember>& m){
const MetaData& md = myMetaData();
for(MetaData::const_iterator i = md.begin();i!= md.end();++i){
this->*(i->second) = m[i->first];
}
}
YourClass(const std::vector<std::pair<std::string,pMember_t>>& m){
const MetaData& md = myMetaData();
for(MetaData::const_iterator i = md.begin();i!= md.end();++i){
this->*(i->second) = m[i->first];
}
}
};
(pretty sure I've got the syntax right but this is a machinery post not a code post)
RE:
in a function, each member has the same exact code done to it as other members, e.g. assignment from a map in a constructor where map key is same as member key
this is handled above.
RE:
The list of members is very fluid, with constant additions and sometimes deletions, some (but not all) driven by changing columns in a DB table.
When you add a new AMember, say newMember, all you have to do is update the MetaData constructor with an:
push_back(make_pair(std::string("newMember"),&YourClass::newMember));
RE:
This identicality of behavior is repeated across many-many functions (>20), of course the behavior in each function is different so there's no way to factor things out.
You have the machinery to apply this same idiom to build the functions
eg: setAllValuesTo(const AMember& value)
YourClass::setAllValuesTo(const AMember& value){
const MetaData& md = myMetaData();
for(MetaData::const_iterator i = md.begin();i!= md.end();++i){
this->*(i->second) = value;
}
}
If you are a tiny bit creative with function pointers or template functionals you can factor out the mutating operation and do just about anything you want to YourClass' AMember's on a collection basis. Wrap these general functions (that may take a functional or function pointer) to implement your current set of 20 public methods in the interface.
If you need more metadata just augment the codomain of the MetaData map beyond a pointer to member. (Of course the i->second above would change then)
Hope this helps.
You can do something like his:
#define DOTHAT(m) m = map[#m]
DOTHAT(member1); DOTHAT(member2);
#undef DOTHAT
That doesn't fully fit your description, but closest to it that saves you typing.
Probably what I'd look to do would be to make use of runtime polymorphism (dynamic dispatch). Make a parent class for those members with a method that does the common stuff. The members derive their class from that parent class. The ones that need a different implementation of the method implement their own. If they need the common stuff done too, then inside the method they can downcast to the base class and call its version of the method.
Then all you have to do inside your original class is call the member for each method.
I would recommend a small command-line app, written in whatever language you or your team are most proficient in.
Add some kind of template language to your source files. For something like this, you don't need to implement a full-fledged parser or anything fancy like that. Just look for an easily-identified character at the beginning of a line, and some keywords to replace.
Use the command-line app to convert the templated source files into real source files. In most build systems, this should be pretty easy to do automatically by adding a build phase, or simply telling the build system: "use MyParser.exe to handle files of type *.tmp"
Here's an example of what I'm talking about:
MyClass.tmp
MyClass::MyClass(SomeMap & map) { // construct an object from a map
▐REPLACE_EACH, LABEL, "intMember1", "intMember2, ... , "intMemberN"
▐ LABEL = map["$Label"];
}
I've used "▐" as an example, but any character that would otherwise never appear as the first character on a line is perfectly acceptable.
Now, you would treat these .tmp files as your source files, and have the actual C++ code generated automatically.
If you've ever heard the phrase "write code that writes code", this is what it means :)
There are already a lot of good answers and ideas here, but for the sake of diversity I'll present another.
In the code file for MyClass would be:
struct MemberData
{
size_t Offset;
const char* ID;
};
static const MemberData MyClassMembers[] =
{
{ offsetof(MyClass, Member1), "Member1" },
{ offsetof(MyClass, Member2), "Member2" },
{ offsetof(MyClass, Member3), "Member3" },
};
size_t GetMemberCount(void)
{
return sizeof(MyClassMembers)/sizeof(MyClassMembers[0]);
}
const char* GetMemberID(size_t i)
{
return MyClassMembers[i].ID;
}
int* GetMemberPtr(MyClass* p, size_t i) const
{
return (int*)(((char*)p) + MyClassMembers[i].Offset);
}
Which then makes it possible to write the desired constructor as:
MyClass::MyClass(SomeMap& Map)
{
for(size_t i=0; i<GetMemberCount(); ++i)
{
*GetMemberPtr(i) = Map[GetMemberID(i)];
}
}
And of course, for any other functions operating on all the members you would write similar loops.
Now there are a few issues with this technique:
Operations on members use a runtime loop as opposed to other solutions which would yield an unrolled sequence of operations.
This absolutely depends on each member having the same type. While that was allowed by OP, one should still evaluate whether or not that might change in the future. Some of the other solutions don't have this restriction.
If I remember correctly, offsetof is only defined to work on POD types by the C++ standard. In practice, I've never seen it fail. However I haven't used all the C++ compilers out there. In particular, I've never used GCC. So you would need to test this in your environment to ensure it actually works as intended.
Whether or not any of these are problems is something you'll have to evaluate against your own situation.
Now, assuming this technique is usable, there is one nice advantage. Those GetMemberX functions can be turned into public static/member functions of your class, thus providing this generic member access to more places in your code.
class MyClass
{
public:
MyClass(SomeMap& Map);
int Member1;
int Member2;
int Member3;
static size_t GetMemberCount(void);
static const char* GetMemberID(size_t i);
int* GetMemberPtr(size_t i) const;
};
And if useful, you could also add a GetMemberPtrByID function to search for a given string ID and return a pointer to the corresponding member.
One disadvantage with this idea so far is that there is a risk that a member could be added to the class but not to the MyClassMembers array. However, this technique could be combined with xtofl's macro solution so that a single list could populate both the class and the array.
changes in the header:
#define MEMBERS\
MEMBER( Member1 )\
SEP MEMBER( Member2 )\
SEP MEMBER( Member3 )\
class MyClass
{
public:
#define SEP ;
#define MEMBER( name ) int name
MEMBERS;
#undef MEMBER
#undef SEP
// other stuff, member functions, etc
};
and changes in the code file:
const MemberData MyClassMembers[] =
{
#define SEP ,
#define MEMBER( name ) { offsetof(MyClass, name), #name }
MEMBERS
#undef MEMBER
#undef SEP
};
Note: I have left error checking out of my examples here. Depending on how this would be used, you might want to ensure the array bounds are not overrun with debug mode asserts and/or release mode checks that would return NULL pointers for bad indexes. Or some use of exceptions if appropriate.
Of course, if you aren't worried about error checking the array bounds, then GetMemberPtr could actually be changed into something else that would return a reference to the member.