Finding An Alternative To Abusing Enums - c++

In a project I've been helping with recently, the entire code base depends on a monstrous enum that's effectively used as keys for a glorified Hash Table. The only problem is now that it is HUGE, compiling whenever the enum changes is basically a rebuild for an already large code base. This takes forever and I would really LOVE to replace it.
enum Values
{
Value = 1,
AnotherValue = 2,
<Couple Thousand Entries>
NumValues // Sentinel value for creating arrays of the right size
}
What I'm looking for is ways to replace this enum but still have a system that is typesafe (No unchecked strings) and also compatible with MSVC2010 (no constexpr). Extra compiling overhead is acceptable as it might still be shorter time to compile than recompiling a bunch of files.
My current attempts can basically be summed up as delaying defining the values until link time.
Examples of its use
GetValueFromDatabase(Value);
AddValueToDatabase(Value, 5);
int TempArray[NumValues];
Edit: Compiletime and Runtime preprocessing is acceptable. Along with basing it off some kind of caching data structure at runtime.

One way you can achieve this is with a key class that wraps the numeric ID and which cannot be directly instantiated, therefore forcing references to be done through a type-safe variable:
// key.h
namespace keys {
// Identifies a unique key in the database
class Key {
public:
// The numeric ID of the key
virtual size_t id() const = 0;
// The string name of the key, useful for debugging
virtual const std::string& name() const = 0;
};
// The total number of registered keys
size_t count();
// Internal helpers. Do not use directly outside this code.
namespace internal {
// Lazily allocates a new instance of a key or retrieves an existing one.
const Key& GetOrCreate(const std::string& name, size_t id);
}
}
#define DECLARE_KEY(name) \
extern const ::keys::Key& name
#define DEFINE_KEY(name, id) \
const ::keys::Key& name = ::keys::internal::GetOrCreate(STRINGIFY(name), id)
With the code above, the definition of keys would look like this:
// some_registration.h
DECLARE_KEY(Value);
DECLARE_KEY(AnotherValue);
// ...
// some_registration.cpp
DEFINE_KEY(Value, 1);
DEFINE_KEY(AnotherValue, 2);
// ...
Importantly, the registration code above could now be split into several separate files, so that you do not need to recompile all the definitions at once. For example, you could break apart the registration into logical groupings, and if you added a new entry, only on the one subset would need to be recompiled, and only code that actually depended on the corresponding *.h file would need to be recompiled (other code that didn't reference that particular key value would no longer need to be updated).
The usage would be very similar to before:
GetValueFromDatabase(Value);
AddValueToDatabase(Value, 5);
int* temp = new int[keys::count()];
The corresponding key.cpp file to accomplish this would look like this:
namespace keys {
namespace {
class KeyImpl : public Key {
public:
KeyImpl(const string& name, size_t id) : id_(id), name_(name) {}
~KeyImpl() {}
virtual size_t id() const { return id_; }
virtual const std::string& name() const { return name_; }
private:
const size_t id_;
const std::string name_;
};
class KeyList {
public:
KeyList() {}
~KeyList() {
// This will happen only on program termination. We intentionally
// do not clean up "keys_" and just let this data get cleaned up
// when the entire process memory is deleted so that we do not
// cause existing references to keys to become dangling.
}
const Key& Add(const string& name, size_t id) {
ScopedLock lock(&mutex_);
if (id >= keys_.size()) {
keys_.resize(id + 1);
}
const Key* existing = keys_[id]
if (existing) {
if (existing->name() != name) {
// Potentially some sort of error handling
// or generation here... depending on the
// desired semantics, for example, below
// we use the Google Log library to emit
// a fatal error message and crash the program.
// This crash is expected to happen at start up.
LOG(FATAL)
<< "Duplicate registration of key with ID "
<< id << " seen while registering key named "
<< "\"" << name << "\"; previously registered "
<< "with name \"" << existing->name() << "\".";
}
return *existing;
}
Key* result = new KeyImpl(name, id);
keys_[id] = result;
return *result;
}
size_t length() const {
ScopedLock lock(&mutex_);
return keys_.size();
}
private:
std::vector<const Key*> keys_;
mutable Mutex mutex_;
};
static LazyStaticPtr<KeysList> keys_list;
}
size_t count() {
return keys_list->length();
}
namespace internal {
const Key& GetOrCreate(const std::string& name, size_t id) {
return keys_list->Add(name, id);
}
}
}
As aptly noted in the comments below, one drawback with an approach that allows for decentralized registration is that it then becomes possible to get into conflict scenarios where the same value is used multiple times (the example code above adds an error for this case, but this occurs at runtime, when it would be really nice to surface such a thing at compile time). Some ways to mitigate this include commit hooks that run tests checking for such a condition or policies on how to select the ID value that reduce the likelihood of reusing an ID, such as a file that indicates the next available ID that must be incremented and submitted as a way to allocate IDs. Alternatively, assuming that you are permitted to reshuffle the IDs (I assumed in this solution that you must preserve the current IDs that you already have), you could change the approach so that the numeric ID is automatically generated from the name (e.g. by taking a hash of the name) and possibly use other factors such as __FILE__ to deal with collisions so that IDs are unique.

Related

Mechanism for Save/Load+Undo/Redo with minimum boilerplate

I want to make an app where a user can edit a diagram (for example), which would provide the standard mechanisms of: Save, Load, Undo, and Redo.
A simple way to do it is to have classes for the diagram and for the various shapes in it, which implement serialization via save and load methods, and where all methods to edit them return UndoableActions that can be added to an UndoManager which calls their perform method and adds them to an undo stack.
The problem with the simple way described above is that it requires a lot of error-prone boilerplate work.
I know that the serialization (save/load) part of the work can be solved by using something like Google's Protocol Buffers or Apache Thrift, which generates the boiler-plate serialization code for you, but it doesn't solve the undo+redo problem. I know that for Objective C and Swift, Apple provides Core Data which does solve serialization + undo, but I'm not familiar with anything similar for C++.
Is there a good way non-error-prone to solve save+load+undo+redo with little boilerplate?
The problem with the simple way described above is that it requires a lot of error-prone boilerplate work.
I am not convinced that this is the case. Your approach sounds reasonable and using Modern C++ features and abstractions you can implement a safe and elegant interface for it.
For starters, you could use std::variant as a sum type for "undoable actions" - this will give you a type-safe tagged union for every action. (Consider using boost::variant or other implementations that can be easily found on Google if you do not have access to C++17). Example:
namespace action
{
// User dragged the shape to a separate position.
struct move_shape
{
shape_id _id;
offset _offset;
};
// User changed the color of a shape.
struct change_shape_color
{
shape_id _id;
color _previous;
color _new;
};
// ...more actions...
}
using undoable_action = std::variant<
action::move_shape,
action::change_shape_color,
// ...
>;
Now that you have a sum type for all your possible "undoable actions", you can define undo behavior by using pattern matching. I wrote two articles on variant "pattern matching" by overloading lambdas that you could find interesting:
"visiting variants using lambdas - part 1"
"visiting variants using lambdas - part 2"
Here's an example of how your undo function could look like:
void undo()
{
auto action = undo_stack.pop_and_get();
match(action, [&shapes](const move_shape& y)
{
// Revert shape movement.
shapes[y._id].move(-y._offset);
},
[&shapes](const change_shape_color& y)
{
// Revert shape color change.
shapes[y._id].set_color(y._previous);
},
[](auto)
{
// Produce a compile-time error.
struct undo_not_implemented;
undo_not_implemented{};
});
}
If every branch of match gets large, it could be moved to its own function for readability. Trying to instantiate undo_not_implemented or using a dependent static_assert is also a good idea: a compile-time error will be produced if you forget to implement behavior for a specific "undoable action".
That's pretty much it! If you want to save the undo_stack so that the history of actions is preserved in saved documents, you can implement a auto serialize(const undoable_action&) that, again, uses pattern matching to serialize the various actions. You could then implement a deserialize function that repopulates the undo_stack on file load.
If you find implementing serialization/deserialization for every action too tedious, consider using BOOST_HANA_DEFINE_STRUCT or similar solutions to automatically generate serialization/deserialization code.
Since you're concerned about battery and performance, I would also like to mention that using std::variant or similar tagged union constructs is on average faster and more lightweight compared to polymorphic hierarchies, as heap allocation is not required and as there is no run-time virtual dispatch.
About redo functionality: you could have a redo_stack and implement an auto invert(const undoable_action&) function that inverts the behavior of an action. Example:
void undo()
{
auto action = undo_stack.pop_and_get();
match(action, [&](const move_shape& y)
{
// Revert shape movement.
shapes[y._id].move(-y._offset);
redo_stack.push(invert(y));
},
// ...
auto invert(const undoable_action& x)
{
return match(x, [&](move_shape y)
{
y._offset *= -1;
return y;
},
// ...
If you follow this pattern, you can implement redo in terms of undo! Simply call undo by popping from the redo_stack instead of the undo_stack: since you "inverted" the actions it will perform the desired operation.
EDIT: here's a minimal wandbox example that implements a match function that takes in a variant and returns a variant.
The example uses boost::hana::overload to generate the visitor.
The visitor is wrapped in a lambda f that unifies the return type to the type of the variant: this is necessary as std::visit requires that the visitor always returns the same type.
If returning a type which is different from the variant is desirable, std::common_type_t could be used, otherwise the user could explicitly specify it as the first template parameter of match.
Two reasonable approaches to this problem are implemented in the frameworks Flip and ODB.
Code-generation / ODB
With ODB you need to add #pragma declarations to your code, and have it's tool generate methods that you use for save/load and for editing the model, like so:
#pragma db object
class person
{
public:
void setName (string);
string getName();
...
private:
friend class odb::access;
person () {}
#pragma db id
string email_;
string name_;
};
Where the accessors declared in the class are auto-generated by ODB so that all changes to the model can get captured and undo-transactions may be made for them.
Reflection with minimal boilerplate / Flip
Unlike ODB, Flip doesn't generate C++ code for you, but rather it requires your program to call Model::declare to re-declare your structures like so:
class Song : public flip::Object
{
public:
static void declare ();
flip::Float tempo;
flip::Array <Track> tracks;
};
void Song::declare ()
{
Model::declare <Song> ()
.name ("acme.product.Song")
.member <flip::Float, &Song::tempo> ("tempo");
.member <flip::Array <Track>, &Song::tracks> ("tracks");
}
int main()
{
Song::declare();
...
}
With the structured declared like so, flip::Object's constructor can initialize all the fields so that they can point to the undo stack, and all the edits on them are recorded. It also has a list of all the members so that flip::Object can implement the serialization for you.
The problem with the simple way described above is that it requires a lot of error-prone boilerplate work.
I would say that the actual problem is that your undo/redo logic is part of a component, that should ship only a bunch of data as a position, a content and so on.
A common OOP way to decouple the undo/redo logic from the data is the command design pattern.
The basic idea is that all the user interactions are converted to commands and those commands are executed on the diagram itself. They contain all the information required to perform an operation and to rollback it, as long as you maintain a sorted list of commands and undo/redo them in order (that is usually the user expectation).
Another common OOP pattern that can help you either to design a custom serialization utility or to use the most common ones is the visitor design pattern.
Here the basic idea is that your diagram should not care about the kind of components it contains. Whenever you want to serialize it, you provide a serializer and the components promote themselves to the right type when queried (see double dispatching for further details on this technique).
That being said, a minimal example is worth more than a thousand words:
#include <memory>
#include <stack>
#include <vector>
#include <utility>
#include <iostream>
#include <algorithm>
#include <string>
struct Serializer;
struct Part {
virtual void accept(Serializer &) = 0;
virtual void draw() = 0;
};
struct Node: Part {
void accept(Serializer &serializer) override;
void draw() override;
std::string label;
unsigned int x;
unsigned int y;
};
struct Link: Part {
void accept(Serializer &serializer) override;
void draw() override;
std::weak_ptr<Node> from;
std::weak_ptr<Node> to;
};
struct Serializer {
void visit(Node &node) {
std::cout << "serializing node " << node.label << " - x: " << node.x << ", y: " << node.y << std::endl;
}
void visit(Link &link) {
auto pfrom = link.from.lock();
auto pto = link.to.lock();
std::cout << "serializing link between " << (pfrom ? pfrom->label : "-none-") << " and " << (pto ? pto->label : "-none-") << std::endl;
}
};
void Node::accept(Serializer &serializer) {
serializer.visit(*this);
}
void Node::draw() {
std::cout << "drawing node " << label << " - x: " << x << ", y: " << y << std::endl;
}
void Link::accept(Serializer &serializer) {
serializer.visit(*this);
}
void Link::draw() {
auto pfrom = from.lock();
auto pto = to.lock();
std::cout << "drawing link between " << (pfrom ? pfrom->label : "-none-") << " and " << (pto ? pto->label : "-none-") << std::endl;
}
struct TreeDiagram;
struct Command {
virtual void execute(TreeDiagram &) = 0;
virtual void undo(TreeDiagram &) = 0;
};
struct TreeDiagram {
std::vector<std::shared_ptr<Part>> parts;
std::stack<std::unique_ptr<Command>> commands;
void execute(std::unique_ptr<Command> command) {
command->execute(*this);
commands.push(std::move(command));
}
void undo() {
if(!commands.empty()) {
commands.top()->undo(*this);
commands.pop();
}
}
void draw() {
std::cout << "draw..." << std::endl;
for(auto &part: parts) {
part->draw();
}
}
void serialize(Serializer &serializer) {
std::cout << "serialize..." << std::endl;
for(auto &part: parts) {
part->accept(serializer);
}
}
};
struct AddNode: Command {
AddNode(std::string label, unsigned int x, unsigned int y):
label{label}, x{x}, y{y}, node{std::make_shared<Node>()}
{
node->label = label;
node->x = x;
node->y = y;
}
void execute(TreeDiagram &diagram) override {
diagram.parts.push_back(node);
}
void undo(TreeDiagram &diagram) override {
auto &parts = diagram.parts;
parts.erase(std::remove(parts.begin(), parts.end(), node), parts.end());
}
std::string label;
unsigned int x;
unsigned int y;
std::shared_ptr<Node> node;
};
struct AddLink: Command {
AddLink(std::shared_ptr<Node> from, std::shared_ptr<Node> to):
link{std::make_shared<Link>()}
{
link->from = from;
link->to = to;
}
void execute(TreeDiagram &diagram) override {
diagram.parts.push_back(link);
}
void undo(TreeDiagram &diagram) override {
auto &parts = diagram.parts;
parts.erase(std::remove(parts.begin(), parts.end(), link), parts.end());
}
std::shared_ptr<Link> link;
};
struct MoveNode: Command {
MoveNode(unsigned int x, unsigned int y, std::shared_ptr<Node> node):
px{node->x}, py{node->y}, x{x}, y{y}, node{node}
{}
void execute(TreeDiagram &) override {
node->x = x;
node->y = y;
}
void undo(TreeDiagram &) override {
node->x = px;
node->y = py;
}
unsigned int px;
unsigned int py;
unsigned int x;
unsigned int y;
std::shared_ptr<Node> node;
};
int main() {
TreeDiagram diagram;
Serializer serializer;
auto addNode1 = std::make_unique<AddNode>("foo", 0, 0);
auto addNode2 = std::make_unique<AddNode>("bar", 100, 50);
auto moveNode2 = std::make_unique<MoveNode>(10, 10, addNode2->node);
auto addLink = std::make_unique<AddLink>(addNode1->node, addNode2->node);
diagram.serialize(serializer);
diagram.execute(std::move(addNode1));
diagram.execute(std::move(addNode2));
diagram.execute(std::move(addLink));
diagram.serialize(serializer);
diagram.execute(std::move(moveNode2));
diagram.draw();
diagram.undo();
diagram.undo();
diagram.serialize(serializer);
}
I've not implemented the redo action and the code is far from being a production-ready piece of software, but it acts quite well as a starting point from which to create something more complex.
As you can see, the goal is to create a tree diagram that contains both nodes an links. A component contains a bunch of data and knows how to draw itself. Moreover, as anticipated, a component accepts a serializer in case you want to write it down on a file or whatever.
All the logic is contained in the so called commands. In the example there are three commands: add node, add link and move node. Neither the diagram nor the components know anything about what's going on under the hood. All what the diagram knows is that it's executing a set of commands and those commands can be executed back a step at the time.
A more complex undo/redo system can contain a circular buffer of commands and a few indexes that indicate the one to substitute with the next one, the one valid when going forth and the one valid when going back.
It's quite easy to implement indeed.
This approach will help you decoupling the logic from the data and it's quite common when dealing with user interfaces.
To be honest, it's not something that came up suddenly to my mind. I found something similar while looking at how open-source software solved the issue and I've used it a few years ago in a software of mine. The resulting code is really easy to maintain.
Another approach you might want to consider is working with inmutable data structures and objects. Then, the undo/redo stack can be implemented as a stack of versions of the scene/diagram/document. Undo() replaces the current version with an older version from the stack, and so on. Because all data is inmutable, you can keep references instead of copies, so it is fast and (relatively) cheap.
Pros:
simple undo/redo
multithread-friendly
clean separation of "structure" and transient state (e.g. current selection)
may simplify serialization
caching/memoization/precomputation-friendly (e.g. bounding-box, gpu buffers)
Cons:
consumes a bit more memory
forces separation of "structure" and transient state
probably more difficult: for example, for a typical tree-like scenegraph, to change a node you would also need to change all the nodes along the path to the root; the old and new versions can share the rest of the nodes
Assuming that you're calling save() on a temporary file for each edit of the diagram (even if user doesn't explicitly call the save action) and that you undo only the latest action, you can do as follows:
LastDiagram load(const std::string &path)
{
/* Check for valid path (e.g. boost::filesystem here) */
if(!found)
{
throw std::runtime_exception{"No diagram found"};
}
//read LastDiagram
return LastDiagram;
}
LastDiagram undoLastAction()
{
return loadLastDiagram("/tmp/tmp_diagram_file");
}
and in your main app you handle the exception if thrown. In case you want to allow more undos, then you should think to a solution like sqlite or a tmp file with more entries.
If performance in time and space are issues due large diagrams, think to implement some strategy like keeping an incremental difference for each element of a diagram in a std::vector (limit it to 3/5 if objects are big) and call the renderer with the current statuses. I'm not an OpenGL expert, but I think it's the way it's done there. Actually you could 'steal' this strategy from game development best practices, or generally graphics related ones.
One of those strategies could be something like this:
A structure for efficient update, incremental redisplay and undo in graphical editors

How to elegantly declare subset of set of variables

lets say that requirement is this:
As a class user I would like to collect information about a subject and when class has enough information I would like for a class to return to me the list of collected data. Enough information is defined as - when all information from subset of all possible information is collected. That subset is not fixed and it is provided to the class.
For example this is list of all possible information:
{
string name;
int age;
char sex;
string location;
}
and I want to give my users a possibility to tell me to listen from some data source(from which my class parses data) until I get the age and sex.
Problem is that I dont know how to convey that without an enum.
Basically my enum solution is listening to data source until I determine using using std::includes on 2 set of enums(collected, required) that I have collected all the data.
Is it possible to do it without enums?
Whenever I want to decouple the implementation of a piece of logic from where it's needed - in this case the knowledge of "how much data is enough" - I think of a callback function.
Presumably the set of all possible data that your class can collect is known (name, age, sex & location in your example). This means all clients of your class (can) know about it also, without increasing the amount of coupling & dependence.
My solution is to create an "evaluator" class that encapsulates this logic. An instance of a subclass of this class is created by the client and handed to the data collector at the time of the initial request for data; this object is responsible for deciding (and telling the "collector") when enough data has been collected.
#include <string>
// The class that decides when enough data has been collected
// (Provided to class "collector" by its clients)
class evaluator
{
public:
virtual ~evaluator() {};
// Notification callbacks; Returning *this aids in chaining
virtual evaluator& name_collected() { return *this; }
virtual evaluator& age_collected() { return *this; }
virtual evaluator& sex_collected() { return *this; }
virtual evaluator& location_collected() { return *this; }
// Returns true when sufficient data has been collected
virtual bool enough() = 0;
};
// The class that collects all the data
class collector
{
public:
void collect_data( evaluator& e )
{
bool enough = false;
while ( !enough )
{
// Listen to data source...
// When data comes in...
if ( /* data is name */ )
{
name = /* store data */
enough = e.name_collected().enough();
}
else if ( /* data is age */ )
{
age = /* store data */
enough = e.age_collected().enough();
}
/* etc. */
}
}
// Data to collect
std::string name;
int age;
char sex;
std::string location;
};
In your example, you wanted a particular client to be able to specify that the combination of age and sex is sufficient. So you subclass evaluator like so:
class age_and_sex_required : public evaluator
{
public:
age_and_sex_required()
: got_age( false )
, got_sex( false )
{
}
virtual age_and_sex_required& age_collected() override
{
got_age = true;
return *this;
}
virtual age_and_sex_required& sex_collected() override
{
got_sex = true;
return *this;
}
virtual bool enough() override
{
return got_age && got_sex;
}
private:
bool got_age;
bool got_sex;
};
The client passes an instance of this class when requesting data:
collector c;
c.collect_data( age_and_sex_required() );
The collect_data method quits and returns when the age_and_sex_required instance reports that the amount of data collected is "enough", and you haven't built any logic, knowledge, enums, whatever, into the collector class. Also, the logic of what constitutes "enough" is infinitely configurable with no further changes to the collector class.
----- EDIT -----
An alternate version would not use a class with the ..._collected() methods but simply a single (typedef'd) function that accepts the collector as a parameter and returns boolean:
#include <functional>
typedef std::function< bool( collector const& ) > evaluator_t;
The code in collector::collect_data(...) would simply call
enough = e( *this );
each time a piece of data is collected.
This would eliminate the necessity of the separate evaluator abstract interface, but would add dependence on the collector class itself, as the object passed as the evaluator_t function would be responsible for checking the state of the collector object to evaluate whether enough data has been collected (and would require the collector to have sufficient public interface to inquire about its state):
bool age_and_sex_required( collector const& c )
{
// Assuming "age" and "sex" are initialized to -1 and 'X' to indicate "empty"
// (This could be improved by changing the members of "collector" to use
// boost::optional<int>, boost::optional<char>, etc.)
return (c.age >= 0) && (c.sex != 'X');
}
Not sure if this will work for you or not, but because each item may or may not be present, boost::optional sprung to mind.
{
boost::optional<string> name;
boost::optional<int> age;
boost::optional<char> sex;
boost::optional<string> location;
}
Your class could then have a bool validate() method which checks the presence of the required set of items. This could either be a class method, or passed in as a callback.
You can define a value by default for each member saying "i'm required".
static const string required_name = /* your default name */;
// ...
You can also use an integer as a bitmask which will behave like a set of enums.
typedef int mask_type;
static const mask_type name_flag = 0x01;
static const mask_type age_flag = 0x02;
static const mask_type sex_flag = 0x04;
static const mask_type location_flag = 0x08;
//...
mask_type required = name_flag | age_flag; // need to collect name & age
collect(&my_instance, required) // collect and set required values
Easy to use and no overhead than a single int :
value is not required anymore : required &= ~xx_flag
no more values required : bool(required)
value is required : bool(required & xx_flag)
...
Enums seems the cleanest way to do this, but I suppose if you preferred you could use short strings with a different character corresponding to each type of data. That's not so clean but might be easier to debug.
Couldnt you accomplish such behaviour by using a template and a abstract class, doing something like this?
class SomeAbstract
{
public:
virtual bool getRequired() = 0;
virtual void setRequired(bool req) = 0;
};
template <class T>
class SomeTemplate
{
T value;
bool required;
public:
TemplateName(T t)
{
value = t;
required = false;
}
void setRequired(bool req)
{
required = req;
}
bool getRequired()
{
return required;
}
void setValue(T newValue)
{
value = newValue;
}
T getValue()
{
return value;
}
};
you can then declare your list of attributes as the same type.
SomeTemplate<string> name;
SomeTemplate<int> age;
SomeTemplate<char> sex;
SomeTemplate<string> location;
Since the template is inheriting the same type you can store them in a std::vector<SomeAbstract> and treat them all the same.
This is not tested code and the idea may have some improvements but i hope you get my point.

How to use a std::string with inheritance as parameter?

I'm currently working on a college project with C++ and one of my assignments is to make a social network using inheritance and polymorphism. Currently I have a Node class that is used on a Map and Multimap (both are created manually and not used from the std). The node can hold two variables (key and data for example) and where I'm using it, the first variable can either be a pointer or a string (they let us use std::string).
The problem I'm having is that when I inherit from the "root" class (Object) and use "Object" as a data type for "key", I'm unable to pass a string created with the std as parameter to its constructor, because it doesn't inherit from my Object class. One solution is to implement my own string class and make it inherit from Object, but I was searching for other workarounds.
If there's any problem with the logic above, please tell me as I'm just beginning with C++.
EDIT 1 (some code for my Node):
class TempNode
{
private:
TempNode* next;
Key key;
T value;
public:
TempNode();
explicit TempNode(const Key thisKey, const T thisValue, TempNode* thisNext = NULL)
: key(thisKey)
, value(thisValue)
, next(thisNext)
{
}
inline Key getKey() { return key; }
inline T getValue() { return value; }
inline TempNode* getNext() { return next; }
inline void setNext(TempNode* thisNext) { next = thisNext; }
};
The string or Person types are currently used only in key, but that is with another implementation using templates (which works fine), but my teacher now requires us to apply inheritance to the entire project (to get used to it I guess).
To implement this using inheritance, you think of Key as a data type specifically designed as a key in your map/multimap implementation. Key inherits from Object, but it may provide its own, key-specific functions, such as – for example – a function repr() which generates a representation used by the map for some map-specific operations (maybe as a basis for hashing, or sorting or whatever).
The map/multimap must be used in such a way that the Key objects are stored as pointers (or std::unique_ptr, or std::shared_ptr, or whatever is appropriate), but not as copies of Key objects.
So we have:
struct Object
{
virtual ~Object()
{ }
};
/* Key class. Pointers of this type are inserted
into the map. */
class Key : public Object
{
public:
/* Must be supported by all keys: */
virtual std::string repr() const = 0;
};
We also assume there is a separate definition of Person objects:
struct Person : Object
{
Person(const std::string &name)
: name_(name)
{ }
std::string name_;
};
According to your specification, there are two flavours of Key: One that represents strings and must be initialized using a string, and another one that represents persons and must be initialized by a person pointer (I'll assume that the person-keys do not actually own these pointers, so you need to make sure the person objects they point to stay alive as long as the person-key exists).
We implement this by specializing Key into two derived classes, a PersonKey and a StringKey:
class PersonKey : public Key
{
public:
PersonKey(Person *person_ptr)
: Key() , person_ptr_(person_ptr)
{ }
virtual std::string repr() const
{
if (person_ptr_ != 0)
return std::string("Person/") + person_ptr_->name_;
else
return "<NUL>";
}
private:
Person *person_ptr_;
};
class StringKey : public Key
{
public:
StringKey(const std::string &str)
: Key() , str_(str)
{ }
virtual std::string repr() const
{
return str_;
}
private:
std::string str_;
};
When you make insertions into your map/multimap, you generate Key objects (which you represent as Key* or Key& or std::unique_ptr<Key>). When you want to insert a string, you generate them as StringKey objects, and when you want to insert them as person-pointers, you use PersonKey – but the data type of the key you insert will not reflect the specialization.
Here is an example of a general Key object (implemented as std::unique_ptr<Key>, but you may just use Key* if you are not afraid of memory leaks):
int main()
{
/* General key object: */
std::unique_ptr<Key> mykey;
/* Now it points to a string-key, initialized using
a string, as required: */
mykey.reset(new StringKey("hello"));
std::cout << "repr(mykey) == \""
<< mykey->repr()
<< '"'
<< std::endl;
/* Now the same key object is made to refer to
a person object: */
Person person("me");
mykey.reset(new PersonKey(&person));
std::cout << "repr(mykey) == \""
<< mykey->repr()
<< '"'
<< std::endl;
return 0;
}
Necessary headers for the code above are:
#include <iostream>
#include <memory>
#include <string>
(But memory is only required for my use of std::unique_ptr, which is not actually necessary to solve your problem.)
I think what you are really looking for are templates. Your solution with "root object" won't work as you can see with standard objects and external libraries but also you will not be able to use your containers with primitives (for example person id(as int) as key, and Person class as value).
With templates you can say what type you are going to work with at compile time and compiler will help you to obey your own rules. It can be declared like this:
template<class T1, class T2>
class Map{
T1 key;
T2 value;
(...)
}
Then you can use it more or less like this:
Map<std::String, int> phoneBook;
And compiler will guard you and warn, if you try to add, for example float instead of int, to you Map. But before you start coding I advice you to read some tutorials first, or maybe even some book on c++ in general. But if you want to start with generic right now, you can start her:
http://www.cplusplus.com/doc/tutorial/templates/
The only way you'd be able to store a string in your Object variable was if the string class inherited from your Object class, so you will have to implement your own String class unfortunately.
The real flaw here is that you are taking a Java/C# approach to design, where an Object variable can hold anything. In C++ the proper way to handle such things is through the use of templates, supposing your Map/Multimap/Node only need to hold one specific data type.
If your container needs to be able to hold any arbitrary data type, I would recommend using type erasure, although that can be a bit complicated for a beginner.

C++ Code Generation

In my epic quest of making C++ do things it shouldn't, I am trying to put together a compile time generated class.
Based on a preprocessor definition, such as (rough concept)
CLASS_BEGIN(Name)
RECORD(xyz)
RECORD(abc)
RECORD_GROUP(GroupName)
RECORD_GROUP_RECORD(foo)
RECORD_GROUP_RECORD(bar)
END_RECORDGROUP
END_CLASS
While I am fairly sure I generate a class that reads the data from the file system using this sort of structure (Maybe even doing it using Template Metaprogramming), I don't see how I can generate both the functions to access the data and the function to read the data.
I would want to end up with a class something like this
class Name{
public:
xyz_type getxyz();
void setxyz(xyz_type v);
//etc
list<group_type> getGroupName();
//etc
void readData(filesystem){
//read xyz
//read abc
//etc
}
};
Does anyone have any idea if this is even possible?
--EDIT--
To clarify the intended usage for this. I have files in a standard format I want to read. The format is defined already, so it is not open to change. Each file can contain any number records, each of which can contain any number sub records.
The numerous record types each contain a diffrent set of sub records, but they can be are defined. So for example the Heightmap record must contain a Heightmap, but can optional contain normals.
So I would want to define a Record for that like so:
CLASS_BEGIN(Heightmap)
RECORD(VHDT, Heightmap, std::string) //Subrecord Name, Readable Name, Type
RECORD_OPTIONAL(VNML, Normals, std::string)
END_CLASS
For which I would want to output something with the functionality of a class like this:
class Heightmap{
public:
std::string getHeightmap(){
return mHeightmap->get<std::string>();
}
void setHeightmap(std::string v){
mHeight->set<std::string>(v);
}
bool hasNormal(){
return mNormal != 0;
}
//getter and setter functions for normals go here
private:
void read(Record* r){
mHeightmap = r->getFirst(VHDT);
mNormal = r->getFirst(VNML);
}
SubRecord* mHeightmap, mNormal;
}
The issue I am having is that I need every preprocessor definition twice. Once for defining the function definition within the class, and once for creating the read function. As the preprocessor is purely functional, I cannot push the data to a queue and generate the class on the END_CLASS marco definition.
I cannot see a way around this issue, but wondered if anyone who has a greater understanding of C++ did.
If you are looking for a way to serialize/deserialize data with C++ code generation, I would look at Google protobufs (http://code.google.com/p/protobuf/) or Facebook's Thrift (http://incubator.apache.org/thrift/).
For protobufs, you write a data definition like so:
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phone = 4;
}
A Person C++ class is then generated that lets you load, save and access this data. You can also generate python, java, etc.
You might be able to solve this problem using boost tuples. It will result in a design which is different to what you are thinking of now, but it should allow you to solve the problem in a generic way.
The following example defines a record of the form "std::string,bool" and then reads that data in from a stream.
#include "boost/tuple/tuple.hpp"
#include <iostream>
#include <sstream>
using namespace ::boost::tuples;
The functions are used to read the data from an istream. The first overload stops the iteration through the tuple after we reach the last record type:
//
// This is needed to stop when we have no more fields
void read_tuple (std::istream & is, boost::tuples::null_type )
{
}
template <typename TupleType>
void read_tuple (std::istream & is, TupleType & tuple)
{
is >> tuple.template get_head ();
read_tuple (is, tuple.template get_tail ());
}
The following class implements the getter member for our Record. Using the RecordKind as our key we get the specific member that we're interested in.
template <typename TupleType>
class Record
{
private:
TupleType m_tuple;
public:
//
// For a given member - get the value
template <unsigned int MBR>
typename element <MBR, TupleType>::type & getMember ()
{
return m_tuple.template get<MBR> ();
}
friend std::istream & operator>> (std::istream & is
, Record<TupleType> & record)
{
read_tuple (is, record.m_tuple);
}
};
The next type is the meta description for our record. The enumeration gives us a symbolic name that we can use to access the members, ie. the field names. The tuple then defines the types of those fields:
struct HeightMap
{
enum RecordKind
{
VHDT
, VNML
};
typedef boost::tuple < std::string
, bool
> TupleType;
};
Finally, we construct a record and read in some data from a stream:
int main ()
{
Record<HeightMap::TupleType> heightMap;
std::istringstream iss ( "Hello 1" );
iss >> heightMap;
std::string s = heightMap.getMember < HeightMap::VHDT > ();
std::cout << "Value of s: " << s << std::endl;
bool b = heightMap.getMember < HeightMap::VNML > ();
std::cout << "Value of b: " << b << std::endl;
}
And as this is all template code, you should be able to have records nested in records.
This is a technique I use a lot in C and C++, called "list macro". Suppose you have a list of things like variables, error messages, interpreter opcodes, or anything about which repetitive code needs to be written. In your case it is class member variables.
Suppose it is variables. Put them in a list macro like this:
#define MYVARS \
DEFVAR(int, a, 6) \
DEFVAR(double, b, 37.3) \
DEFARR(char, cc, 512) \
To declare the variables, do this:
#define DEFVAR(typ,nam,inival) typ nam = inival;
#define DEFARR(typ,nam,len) typ nam[len];
MYVARS
#undef DEFVAR
#undef DEFARR
Now you can generate any sort of repetitive code just by redefining DEFVAR and DEFARR, and instantiating MYVARS.
Some people find this rather jarring, but I think it's a perfectly good way to use the preprocessor as a code generator, and accomplish DRY. And, the list macro itself becomes a mini-DSL.
I might play around with a record mixin to do something similar -- add functionality to a class automagically at compile time
template<class Base, class XyzRecType>
class CRecord : public Base
{
protected:
RecType xyz;
public:
CRecord() : Base() {}
RecType Get() {return xyz;}
void Set(const RecType& anXyz) {xyz = anXyz;}
void ReadFromStream( std::istream& input)
{
...
}
};
class CMyClass
{
};
int main()
{
// now thanks to the magic of inheritance, my class has added methods!
CRecord<CMyClass, std::string> myClassWithAStringRecord;
myClassWithAStringRecord.Set("Hello");
}
In general you can accomplish exactly what you want if you merge everything into one macro and then leverage Booost Preprocessor library to define your class. Look at how I implemented the MACE_REFLECT macro which does a partial specialization of an entire class and must reference each name twice in different parts.
This is very similar to how I automatically parse JSON into structs with the help of the pre-processor.
Given your example, I would translate it as such:
struct Name {
xyz_type xyz;
abc_type abc;
boost::optional<foo_type> foo;
boost::optional<bar_type> bar;
};
MACE_REFLECT( Name, (xyz)(abc)(foo)(bar) )
I can now 'visit' the members of Name from my parser:
struct visitor {
template<typename T, T p>
inline void operator()( const char* name )const {
std::cout << name << " = " << c.*p;
}
Name c;
};
mace::reflect::reflector<Name>::visit(visitor());
If your objects can be represented as structs, arrays, key-value-pairs and primitives, then this technique works wonders and gives me instant serialization/deserializtion to/from json/xml or your custom record format.
https://github.com/bytemaster/mace/blob/master/libs/rpc/examples/jsonv.cpp
I'm not exactly sure what you're looking for in some cases.
What happens to foo and bar in the specification?
What does getGroupName actually return? (foo,bar)? or GroupName?
It looks like you're trying to create a mechanism for loading and accessing on-disk structures of arbitrary layout. Is this accurate? (Edit: Just noticed the "set" member function... so I guess you're looking for full serialization)
If you're on a *nix system, specifying your own compiler to compile to .o (likely a perl/python/what-have-you script that finishes with a call to gcc) in the Makefile is a trivial solution. Others might know of ways of doing this on windows.

Static vs. member variable

For debugging, I would like to add some counter variables to my class. But it would be nice to do it without changing the header to cause much recompiling.
If Ive understood the keyword correctly, the following two snippets would be quite identical. Assuming of course that there is only one instance.
class FooA
{
public:
FooA() : count(0) {}
~FooA() {}
void update()
{
++count;
}
private:
int count;
};
vs.
class FooB
{
public:
FooB() {}
~FooB() {}
void update()
{
static int count = 0;
++count;
}
};
In FooA, count can be accessed anywhere within the class, and also bloats the header, as the variable should be removed when not needed anymore.
In FooB, the variable is only visible within the one function where it exists. Easy to remove later. The only drawback I can think of is the fact that FooB's count is shared among all instances of the class, but thats not a problem in my case.
Is this correct use of the keyword? I assume that once count is created in FooB, it stays created and is not re-initialized to zero every call to update.
Are there any other caveats or headsup I should be aware of?
Edit: After being notified that this would cause problems in multithreaded environments, I clarify that my codebase is singlethreaded.
Your assumptions about static function variables are correct. If you access this from multiple threads, it may not be correct. Consider using InterlockedIncrement().
What you really want, for your long term C++ toolbox is a threadsafe, general purpose debug counters class that allows you to drop it in anywhere and use it, and be accessible from anywhere else to print it. If your code is performance sensitive, you probably want it to automatically do nothing in non-debug builds.
The interface for such a class would probably look like:
class Counters {
public:
// Counters singleton request pattern.
// Counters::get()["my-counter"]++;
static Counters& get() {
if (!_counters) _counters = new Counters();
}
// Bad idea if you want to deal with multithreaded things.
// If you do, either provide an Increment(int inc_by); function instead of this,
// or return some sort of atomic counter instead of an int.
int& operator[](const string& key) {
if (__DEBUG__) {
return _counter_map.operator[](key);
} else {
return _bogus;
}
}
// you have to deal with exposing iteration support.
private:
Counters() {}
// Kill copy and operator=
void Counters(const Counters&);
Counters& operator=(const Counters&);
// Singleton member.
static Counters* _counters;
// Map to store the counters.
std::map<string, int> _counter_map;
// Bogus counter for opt builds.
int _bogus;
};
Once you have this, you can drop it in at will wherever you want in your .cpp file by calling:
void Foo::update() {
// Leave this in permanently, it will automatically get killed in OPT.
Counters::get()["update-counter"]++;
}
And in your main, if you have built in iteration support, you do:
int main(...) {
...
for (Counters::const_iterator i = Counters::get().begin(); i != Countes::get().end(); ++i) {
cout << i.first << ": " << i.second;
}
...
}
Creating the counters class is somewhat heavy weight, but if you are doing a bunch of cpp coding, you may find it useful to write once and then be able to just link it in as part of any lib.
The major problems with static variables occur when they are used together with multi-threading. If your app is single-threaded, what you are doing is quite correct.
What I usually do in this situation is to put count in a anonymous namespace in the source file for the class. This means that you can add/remove the variable at will, it can can used anywhere in the file, and there is no chance of a name conflict. It does have the drawback that it can only be used in functions in the source file, not inlined functions in the header file, but I think that is what you want.
In file FooC.cpp
namespace {
int count=0;
}
void FooC::update()
{
++count;
}