Non-deferred initialization of local static objects? - c++

Is there any pattern or other nonstandard mechanism for either gcc (4.8) or icc (14.0) that can guarantee the early, safe construction of static locals?
I need a global collection of local static objects references for the purposes of coarse profiling controllable at run-time. I am actively hurt by standard deferred construction (as well as by dealing with locked or redundant thread_local collections), and it would be highly advantageous to have complete point lists at start time.
Any hope to achieve this?
#include <iostream>
#include <deque>
// Really want to build this list before main() started!
struct ProfilePoint;
static std::deque<ProfilePoint *> pps;
// Costly construction, but only ever with literal/constexpr params.
// Templating, etc., also discourages non-local building in reality.
struct ProfilePoint {
ProfilePoint(int id, char const *i) : id_(id), inf_(i) { pps.push_back(this); }
void doStuff() { /* ... */ }
int id_;
char const *const inf_;
};
// Functions like this will be called concurrently in reality.
void bar(int cnt) {
for (int i = 0; i < cnt; ++i) {
// Dropping in a local definition/call should be enough to hook in to system
static ProfilePoint pp(2, "description in a string literal");
pp.doStuff();
/* ... */
}
}
void dump() {
std::cout << "[";
for (ProfilePoint *pp: pps) { std::cout << " " << pp->id_ << ":" << pp->inf_; }
std::cout << " ]" << std::endl;
}
int main() { dump(); bar(5); dump(); } // "[ ]" then "[ 2 ]" in gcc/icc
I've read up on Schwarz Counters and sections 3.6.2 (basic.start.init) / 6.7 (stmt.decl) of the C++11 spec, but I don't have as much knowledge about compiler-specific behavior and haven't been able to find anyone else posting about trying to achieve this trick.
Accepted answer:
As John notes below, all classes (may) have their static members initialized before main(), but given that C++11 §9.4.2/5 [class.static.data] and §9.8/4 [class.local] forbid static data members in local classes, a class that is templated over a local class and has a static data member of that class can have its initialization done at start-time. Quite a brilliant insight, and even more subtle than I first thought!
// John Bandela's solutions (slightly condensed):
template <class TPPDesc> struct PPWrapper_T { static ProfilePoint p; };
template <class TPPDesc>
ProfilePoint PPWrapper_T<TPPDesc>::p(TPPDesc::id(), TPPDesc::desc());
#define PROFILE_POINT(ID, DESC, NAME) \
struct ppdef_##NAME { \
static int id() { return ID; } \
static char const *desc() { return DESC; } \
}; \
static PPWrapper_T<ppdef_##NAME> NAME // semicolon must follow!
// ...
void foo() {
PROFILE_POINT(2, "another_description", pp);
pp.p.doStuff();
}
Note also that using a Meyers singleton method for the collection completes the overall safety of this approach. The collection may have to be locked to guard against concurrent static initializations of the points, however. I still need to check spec to confirm the specification for this and whether the static member initialization is actually forced to be done before main().

Try this
#include <iostream>
#include <deque>
// Really want to build this list before main() started!
struct ProfilePoint;
static std::deque<ProfilePoint *> pps;
// Costly construction, but only ever with literal/constexpr params.
// Templating, etc., also discourages non-local building in reality.
struct ProfilePoint {
ProfilePoint(int id, char const *i) : id_(id), inf_(i) { pps.push_back(this); }
void doStuff() { /* ... */ }
int id_;
char const *const inf_;
};
template<class IdDescription>
struct ProfilePoint_{
static ProfilePoint p;
};
template<class IdDescription>
ProfilePoint ProfilePoint_<IdDescription>::p( IdDescription::id(), IdDescription::description() );
#define PROFILE_POINT(theid,thedescription) \
struct ppdef_static_class{ \
static int id(){ return theid; } \
static const char* description(){ return thedescription; } \
};\
static ProfilePoint_<ppdef_static_class>
// Functions like this will be called concurrently in reality.
void bar(int cnt) {
for (int i = 0; i < cnt; ++i) {
// Dropping in a local definition/call should be enough to hook in to system
PROFILE_POINT(2, "description is a string literal") pp;
pp.p.doStuff();
/* ... */
}
}
void dump() {
std::cout << "[";
for (ProfilePoint *pp : pps) { std::cout << " " << pp->id_ << ":" << pp->inf_; }
std::cout << " ]" << std::endl;
}
int main() { dump(); bar(5); dump(); } // Does what you want
This works for MSVC 2013 and ideone http://ideone.com/Z3n1U0
This does require use of macro and to call doStuff() you have to do .p.doStuff(). You also cannot have more than 1 profile point in a function (but this can easily be fixed).
This works by defining a local class that is used as a parameter to a template class that has a static member. By referencing that template in the function, you force the compiler to instantiate the static member of the template.
Let me know if you have any questions about this technique.

You might do it like:
#include <iostream>
#include <deque>
#include <memory>
#include <map>
class ProfilePoint
{
public:
typedef unsigned Identifier;
private:
struct Data {
Identifier id;
const char* information;
unsigned count;
Data(Identifier id, const char* information)
: id(id), information(information), count(0)
{}
};
public:
static void dump();
const char* information() const { return m_data.information; }
Identifier id() const { return m_data.id; }
ProfilePoint(const char* information)
: m_data(*get_data(0, information))
{}
void apply() const {
++m_data.count;
}
private:
static Data* get_data(Identifier, const char* information);
Data& m_data;
};
ProfilePoint::Data* ProfilePoint::get_data(Identifier id, const char* information) {
typedef std::deque<Data> StaticData;
StaticData static_data;
if( ! information) return &static_data[id];
else {
static_data.push_back(Data(static_data.size(), information));
for(auto d: static_data)
std::cout << d.information << std::endl;
return &static_data.back();
}
return 0;
}
void ProfilePoint::dump() {
std::cout << "dump" << std::endl;
Data* data;
for(Identifier i = 0; (data = get_data(i, 0)); ++i) {
std::cout
<< "Profile Point: " << data->information
<< ", Count: " << data->count << std::endl;
}
}
namespace {
ProfilePoint pf("Function");
void f() {
pf.apply();
pf.apply();
pf.apply();
ProfilePoint::dump();
}
} // namespace
int main()
{
f();
return 0;
}
This maintains a single instance of a profile point container in a function and initialize each profile point during translation unit initialization.

Related

C++ Using container as a template type

I am trying to supply the underlying container/data structure for a class via template argument. I'd like to have the underlying container always contain a certain pointer type and I want the maximum amount of variable allowed to be stored to be limited, no matter which container is used.
I managed to make something simple work for std::vector and std::array .
However, for the std::array example there are some weird things I have to do so it compiles.
Here is the test code:
#include <iostream>
#include <type_traits>
#include <vector>
#include <array>
#include <algorithm>
#include <map>
class CustomVariableIF {
public:
void getFoo() const {
std::cout << "Moh!" << std::endl;
return;
}
};
template <typename T>
class CustomVariable: public CustomVariableIF {
public:
CustomVariable(T initValue): value(initValue) {}
void setValue(T newValue) {
value = newValue;
}
T getValue() const {
return value;
}
private:
T value = 0;
};
template <typename TContainer>
class CustomVariableSetBase {
public:
using value_type = typename TContainer::value_type;
/* This allows std::array, std::vector and std::map as underlying container */
static_assert(std::is_same<value_type, CustomVariableIF*>::value or
std::is_same<value_type, std::pair<const uint32_t, CustomVariableIF*>>::value,
"Invalid template type!");
CustomVariableSetBase(const size_t maxFillCount): maxFillCount(maxFillCount) {}
virtual~ CustomVariableSetBase() {};
template<class Q = TContainer>
typename std::enable_if<std::is_same<typename Q::value_type, CustomVariableIF*>::value>::type
callFoos() {
size_t currentIdx = 0;
for (auto& var: container) {
if(var == nullptr) {
return;
}
if(currentIdx < fillCount) {
var->getFoo();
currentIdx++;
}
}
}
/* Used if underlying container is a std::map */
template<class Q = TContainer> typename
std::enable_if<std::is_same<typename Q::value_type,
std::pair<const uint32_t, CustomVariableIF*>>::value>::type
callFoos() {
for (auto& var: container) {
var.second->getFoo();
}
}
protected:
virtual void registerVariable(CustomVariableIF* variable) = 0;
TContainer container;
size_t fillCount = 0;
const size_t maxFillCount;
};
class CustomVariableMap: public CustomVariableSetBase<std::map<uint32_t, CustomVariableIF*>> {
public:
CustomVariableMap(const size_t maxVars): CustomVariableSetBase(maxVars) {};
virtual~ CustomVariableMap() {};
void registerVariable(CustomVariableIF* variable) override {
if(fillCount < maxFillCount) {
container.emplace(idCounter, variable);
lastId = idCounter;
idCounter++;
fillCount++;
}
else {
std::cerr << "CustomVariableMap::registerVariable: Map container is full!" << std::endl;
}
return;
}
uint32_t getIdOfLastAddedVariable() const {
return lastId;
}
private:
uint32_t idCounter = 0;
uint32_t lastId = 0;
};
class CustomVariableSet: public CustomVariableSetBase<std::vector<CustomVariableIF*>> {
public:
CustomVariableSet(const size_t maxVars): CustomVariableSetBase(maxVars) {};
virtual~ CustomVariableSet() {};
void registerVariable(CustomVariableIF* variable) override {
if(fillCount < maxFillCount) {
container.push_back(variable);
fillCount++;
}
else {
std::cerr << "CustomVariableSet::registerVariable: Vector container is full!" <<
std::endl;
}
return;
}
private:
};
template <uint8_t NUM_VARIABLES>
class CustomVariableStaticSet:
public CustomVariableSetBase<std::array<CustomVariableIF*, NUM_VARIABLES>> {
public:
using ArrayBase = std::array<CustomVariableIF*, NUM_VARIABLES>;
CustomVariableStaticSet(): CustomVariableSetBase<ArrayBase>(NUM_VARIABLES) {};
virtual void registerVariable(CustomVariableIF* variable) {
if(this->fillCount < NUM_VARIABLES) {
this->container[this->fillCount] = variable;
this->fillCount++;
}
else {
std::cerr << "CustomVariableStaticSet::registerVariable: Array container is full!" <<
std::endl;
}
}
private:
};
int main() {
using namespace std;
CustomVariableSet testSet(2);
CustomVariableStaticSet<5> testSet2;
CustomVariableMap testSet3(2);
CustomVariable<int> someVar1(5);
testSet.registerVariable(&someVar1);
testSet.registerVariable(&someVar1);
std::cout << "Moh! should be printed twice!" << std::endl;
testSet.callFoos();
testSet2.registerVariable(&someVar1);
testSet2.registerVariable(&someVar1);
std::cout << "Moh! should be printed twice!" << std::endl;
testSet2.callFoos();
testSet3.registerVariable(&someVar1);
testSet3.registerVariable(&someVar1);
std::cout << "Moh! should be printed twice!" << std::endl;
testSet3.callFoos();
std::cout << "Should yield two errors!" << std::endl;
testSet.registerVariable(&someVar1);
testSet2.registerVariable(&someVar1);
testSet3.registerVariable(&someVar1);
}
The class which has std::vector as the underlying container works like I expected.
For the std::array one, I have to write the whole template typename again in the constructor initializer list. I also have to write this-> everytime I try to access a member of the base class.
Can anyone explain to me why I have to do these steps for the class using std::array? Thanks a lot in advance!
Kind Regards
RM
Alright, after some more research I found the more in-depth answer here:
https://isocpp.org/wiki/faq/templates#nondependent-name-lookup-members
(Question: Why am I getting errors when my template-derived-class uses a member it inherits from its template-base-class?)
A very useful read in general when working with templates. I also updated my test code to include an implementation for std::map as the underlying container, which was tricky because the value type is actually different than for the other two containers. There are still some nullptr checks and some other things missing to be really clean, but it worked for me and maybe it can help some other people.

pass userData from callback-begin to callback-end

How to appropriately cache userData that is generated from user's callbackBegin() and send it to user's callbackEnd().
Simple version (No userData - demo)
I want to create a complex database that support callback. For MCVE, let's say it is MyArray.
Here is a simple array class that supports callback but no userData.
#include <iostream>
template<class Derived>class MyArray{ //library - I design it.
public: void push_back(int s){
static_cast<Derived*>(this)->callbackBegin(s);
//do something about array
static_cast<Derived*>(this)->callbackEnd(s);
}
//other fields / functions
};
class Callback : public MyArray<Callback>{ //user's class
public: void callbackBegin(int s){
std::cout<<"callbackBegin"<<std::endl;
}
public: void callbackEnd(int s){
std::cout<<"callbackEnd"<<std::endl;
}
};
int main() {
Callback c;
c.push_back(5); //print: callbackBegin callbackEnd
return 0;
}
It works correctly.
The next step : I want to pass some userData from Callback::callbackBegin() to Callback::callbackEnd().
For example, userData is a clock time when Callback::callbackBegin() is called.
My poor solution (void*& userdata : demo)
Here is my attempt to implement it :-
#include <iostream>
#include <time.h>
template<class Derived>class MyArray{
public: void push_back(int s){
void* userData=nullptr; //#
static_cast<Derived*>(this)->callbackBegin(s,userData); //# ugly
//do something about array
static_cast<Derived*>(this)->callbackEnd(s,userData); //# ugly
}
};
class Callback : public MyArray<Callback>{
public: void callbackBegin(int s,void*& userData){ //#
userData=new clock_t(clock()); //# danger
std::cout<<"callbackBegin"<<std::endl;
}
public: void callbackEnd(int s,void*& userData){ //#
clock_t* userDataTyped=static_cast<clock_t*>(userData);
clock_t clock2=clock();
clock_t different=clock2 - (*userDataTyped);
std::cout<<"callbackEnd time(second)="
<<((float)different)/CLOCKS_PER_SEC<<std::endl;
delete userDataTyped; //# danger
}
};
int main() {
Callback c;
c.push_back(5); //print: callbackBegin callbackEnd time(second)=8.5e-05
return 0;
}
It also works correctly, but I believe it is a bad design (at various #) :-
new/delete in 2 places : potential memory leaking.
Strong pointer is preferred, but I don't know how to.
static_cast<clock_t*>(userData) is code-smell, at least for me.
(minor issue) an extra ugly parameter void*&
Question: What are design patterns / C++ magic to avoid such issues, while make MyArray concise, easy to use, maintainable (i.e. not much worse than the Simple version)?
Other notes:
In real cases, <5% of user's callback classes need userData.
Thus, I feel very reluctant to add void&* as an extra parameter.
Clarify: (edited) The minority cases usually need different types of userData e.g. Callback1 need clock_t, Callback2 need std::string, etc.
Proposed solution should restrain from using std::function<> or virtual function, because the performance is a major concern here.
Thank.
Pass data through a void pointer is a good C solution but (IMHO) not a C++ (specially: not a C++11/c++14/C++17, with auto and std::tuple) good one.
So I suggest to return a value from callbackBegin() and pass the value as first argument to `callbackEnd(); something like
auto r = static_cast<Derived*>(this)->callbackBegin(s);
static_cast<Derived*>(this)->callbackEnd(r, s);
Observe (C++11 and newer magic) that using auto as type of the value returned by callbackBegin(), you can return different types from different `callbackBegin().
Bonus suggestion: be more generic in MyArray::push_back(): using variadic templates, there is no need of fix the number and the types of arguments received by callbackBack() and callbackEnd().
Using variadic templates you can modify push_back() as follows
template <typename ... Args>
void push_back (Args const & ... args)
{
auto r = static_cast<Derived*>(this)->callbackBegin(args...);
static_cast<Derived*>(this)->callbackEnd(r, args...);
}
The following is a full working example with two different callback classes (with different number of arguments and different return types)
#include <tuple>
#include <iostream>
template <typename derT>
struct myA
{
template <typename ... Args>
void push_back (Args const & ... args)
{
auto r = static_cast<derT*>(this)->callbackBegin(args...);
static_cast<derT*>(this)->callbackEnd(r, args...);
}
};
struct cb1 : public myA<cb1>
{
int callbackBegin (int s)
{ std::cout << "cb1 b" << std::endl; return s+5; }
void callbackEnd (int r, int s)
{ std::cout << "cb1 e -" << r << ", " << s << std::endl; }
};
struct cb2 : public myA<cb2>
{
std::tuple<std::string, int> callbackBegin (std::string const & name,
int num)
{ std::cout << "cb2 b" << std::endl; return {name+";", num+1}; }
void callbackEnd (std::tuple<std::string, int> const &,
std::string const & name, int num)
{ std::cout << "cb2 e -" << name << ", " << num << std::endl; }
};
int main ()
{
cb1 c1;
c1.push_back(5);
cb2 c2;
c2.push_back("string arg", 7);
return 0;
}
std::any would allow you to hold clock_t (or any other) object and do away with the void* pointers, however that's a C++17 concept and not yet widely available (although there are implementations such as boost::any).
In the meantime, your code may benefit from a little composition over inheritance, as array and callback are conceptually pretty different and don't seem to belong in the same inheritance hierarchy. So, preferring composition, the code might look something like:
template<class T> struct ICallback
{
virtual void callbackBegin(int s, std::unique_ptr<T>& p) = 0;
virtual void callbackEnd(int s, std::unique_ptr<T>& p) = 0;
};
template<class T> class MyArray
{
public:
MyArray(std::shared_ptr<ICallback<T>> cb) { callback = cb; }
void push_back(int s)
{
callback->callbackBegin(s, usrDataPtr);
//do something about array
callback->callbackEnd(s, usrDataPtr);
}
protected:
std::shared_ptr<ICallback<T>> callback;
std::unique_ptr<T> usrDataPtr;
};
class ClockCallback : public ICallback<clock_t>
{
public:
void callbackBegin(int s, std::unique_ptr<clock_t>& c){
c = std::make_unique<clock_t>(clock());
std::cout << "callbackBegin" << std::endl;
}
void callbackEnd(int s, std::unique_ptr<clock_t>& c){
clock_t clock2 = clock();
clock_t different = clock2 - (*c);
std::cout << "callbackEnd time(second)="
<< ((float)different) / CLOCKS_PER_SEC << std::endl;
}
};
int main() {
std::shared_ptr<ClockCallback> c = std::make_shared<ClockCallback>();
MyArray<clock_t> ma(c);
ma.push_back(7);
return 0;
}
You can use a smart pointer to avoid manually deleting your userData
std::unique_ptr<clock_t> userData;
pass it as a reference to your callbacks
void callbackBegin(int s, std::unique_ptr<clock_t> &userData)
and initialize it this way
userData = std::make_unique<clock_t>(clock())
The C++ magic you're asking about is a known as a virtual method. Virtual method is one of the C++ native ways to implement the callback:
class MyArray{
public:
void push_back(int s) {
const auto userData = callbackBegin(s); //# beautiful
//do something about array
callbackEnd(s, userData); //# beautiful
}
private:
virtual clock_t callbackBegin(int) const = 0;
virtual void callbackEnd(int, const clock_t&) const = 0;
};
class Callback : public MyArray{
clock_t callbackBegin(int s) const final {
std::cout<<"callbackBegin"<<std::endl;
return clock(); //# safe
}
void callbackEnd(int s,const clock_t& userData) const final { //#
const auto different = clock() - userDataTyped;
std::cout << "callbackEnd time(second)=";
std::cout << different/CLOCKS_PER_SEC << std::endl;
//# safe
}
};
Another way is to pass two callable objects to the MyArray ctor and using those objects in the push_back method. The callable objects shall store calls to the relevant class Callback methods. Use std::function to implement those callable objects.

C++ virtual method, that doesn't require "this" pointer - optimization

I'd like to implement access to a certain class:
class A { some properties and methods };
The problem is there are multiple states A can be in and the methods need to behave accordingly. One way is this:
class A
{
void Method1() {
if (A is in state 1) { do something }
else if (A is in state 2) { do something else }
...
}
};
That obviously isn't very optimal, if the methods are called many times. So a solution, which is simple to implement, would be to create several classes for different states:
class A
{
class State1 {
virtual void Method1(A& a) { do something; }
...
} State1Instance;
class State2 { ... }
...
};
And then manage a pointer to the object depending on current state (e.g. State1Instance) and call methods of this object. That avoids the CPU consuming condition.
BUT the State# methods also receive the completely useless "this" pointer to the State object. Is there a way to avoid this? I know the difference is minimal, but I'm trying to make this as optimal as possible and using a CPU register for a completely pointless value is not ideal. This would actually be a good use for "virtual static", which is forbidden however.
Just use good old function pointers if you're really concerned about the repeated branches, which usually you shouldn't.
struct A
{
using StateFn = void (*)(A&);
static void State1(A& a) { a.i = 42; }
static void State2(A& a) { a.i = 420; }
void Method1() { s(*this); }
StateFn s = State1;
int i;
};
If you have multiple methods associated with each state, a table of methods can be constructed as such
struct A
{
static void State1M1(A& a) { a.i = 42; }
static void State2M1(A& a) { a.i = 420; }
static int State1M2(A& a) { return a.i * 42; }
static int State2M2(A& a) { return a.i * 420; }
// The naming sucks, you should find something better
static constexpr struct {
void (*Method1)(A&);
int (*Method2)(A&);
} State[] = {{State1M1, State1M2}, {State2M1, State2M2}};
void Method1() { State[s].Method1(*this); }
int Method2() { return State[s].Method2(*this); }
int s, i;
};
I'm curious if this is even a speedup over a switch statement, do benchmark before you adopt it. You really aren't doing something too different from polymorphism, in a rather un-optimized manner, when you start constructing a method table like in the second case.
If you really want to go with this, use free or static functions, not polymorphy, and encapsulate them with ::std::function. You can even use lambdas, here.
class A {
public:
::std::function<void(A*)> state = func1;
static void func1(A* that) {
::std::cout << "func1\n";
that->state = func2;
}
static void func2(A* that) {
::std::cout << "func2\n";
that->state = [](A* that) { ::std::cout << "lambda\n"; that->state = func1; };
}
public:
void method() {
state(this);
}
};
However, in most cases a switch or else if block would be better as it can be optimised by the compiler, which may translate it into a jump table. If in doubt, benchmark it!
One of the most versatile solutions available out of the box in c++17, and courtesy of boost prior is the variant type and the concept of a static_visitor.
Using c++14 and boost::variant I have created a very simple state machine that uses type-based switching of code paths plus automatic catching of un-accounted-for state/event combinations.
For a fuller solution I would refer you to the boost fsm header-only library.
#include <boost/variant.hpp>
#include <iostream>
#include <typeinfo>
struct event1 {
};
struct event2 {
};
struct state_machine {
struct state1 {
};
struct state2 {
};
struct state3 {
};
using state_type = boost::variant<state1, state2, state3>;
struct handle_event {
// default case for event/state combinations we have not coded for
template<class SM, class State, class Event>
void operator()(SM &sm, State &state, Event const&event) const {
std::cout << "unhandled event "
"state=" << typeid(state).name() << " "
"event=" << typeid(event).name() << std::endl;
}
template<class SM>
void operator()(SM &sm, state1 &state, event1 const&event) const {
std::cout << "received event1 while in state1 - switching to state 2" << std::endl;
sm.change_state(state2());
}
template<class SM>
void operator()(SM &sm, state2 &state, event2 const&event) const {
std::cout << "received event2 while in state2 - switching to state 1" << std::endl;
sm.change_state(state1());
}
template<class SM>
void operator()(SM &sm, state1 &state, event2 const&event) const {
std::cout << "received event2 while in state1 - switching to state 3" << std::endl;
sm.change_state(state3());
}
};
template<class Event>
auto notify_event(Event const&evt) {
return boost::apply_visitor([this, &evt](auto& state)
{
handle_event()(*this, state, evt);
}, state_);
}
template<class NewState>
void change_state(NewState&& ns) {
state_ = std::forward<NewState>(ns);
}
private:
state_type state_ = state1{};
};
int main()
{
state_machine sm {};
sm.notify_event(event1());
sm.notify_event(event2());
sm.notify_event(event2());
// we have not coded for this one
sm.notify_event(event2());
}
example output (exact output will depend on compiler ABI):
received event1 while in state1 - switching to state 2
received event2 while in state2 - switching to state 1
received event2 while in state1 - switching to state 3
unhandled event state=N13state_machine6state3E event=6event2

C++: Monitoring multiple value types

I want to write a class that can monitor a bunch of different values for easy debugging. Imagine setting "watches" in a visual debugger. I'm picturing something like this:
struct Foo {
int x = 0;
std::string s = "bar";
};
int main() {
Foo f;
ValueMonitor::watch("number", &f.x);
ValueMonitor::watch("string", &f.s);
for (int i = 0; i < 10; ++i) {
++f.x;
if (i > 5) {
f.s = "new string";
}
// print the current value of the variable with the given key
// these should change as the loop goes on
ValueMonitor::print("number");
ValueMonitor::print("string");
// or
ValueMonitor::printAll();
// obviously this would be unnecessary in this example since I
// have easy access to f, but imagine monitoring different
// values from all over a much larger code base
}
}
Then these could be easily monitored somewhere in the application's GUI or whatever.
However, I don't know how to handle the different types that would be stored in this class. Ideally, I should be able to store anything that has a string representation. I have a few ideas but none of them really seem right:
Store pointers to a superclass that defines a toString function or operator<<, like Java's Object. But this would require me to make wrappers for any primitives I want to monitor.
Something like boost::any or boost::spirit::hold_any. I think any needs to be type casted before I can print it... I guess I could try/catch casting to a bunch of different types, but that would be slow. hold_any requires defined stream operators, which would be perfect... but I can't get it to work with pointers.
Anyone have any ideas?
I found a solution somewhere else. I was pretty blown away, so might as well post it here for future reference. It looks something like this:
class Stringable
{
public:
virtual ~Stringable() {};
virtual std::string str() const = 0;
using Ptr = std::shared_ptr<Stringable>;
};
template <typename T>
class StringableRef : public Stringable
{
private:
T* _ptr;
public:
StringableRef(T& ref)
: _ptr(&ref) {}
virtual ~StringableRef() {}
virtual std::string str() const
{
std::ostringstream ss;
ss << *_ptr;
return ss.str();
}
};
class ValueMonitor
{
private:
static std::map<std::string, Stringable::Ptr> _values;
public:
ValueMonitor() {}
~ValueMonitor() {}
template <typename T>
static void watch(const std::string& label, T& ref)
{
_values[label] = std::make_shared<StringableRef<T>>(ref);
}
static void printAll()
{
for (const auto& valueItr : _values)
{
const String& name = valueItr.first;
const std::shared_ptr<Stringable>& value = valueItr.second;
std::cout << name << ": " << value->str() << std::endl;
}
}
static void clear()
{
_values.clear();
}
};
std::map<std::string, Stringable::Ptr> ValueMonitor::_values;
.
int main()
{
int i = 5;
std::string s = "test"
ValueMonitor::watch("number", i);
ValueMonitor::watch("string", s);
ValueMonitor::printAll();
i = 10;
s = "new string";
ValueMonitor::printAll();
return 0;
}

how to define an extensible C++ enum system

I have encounter a problem in my project on enums.
In EventDef.h,
enum EventDef {
EVT1 = 0,
EVT2,
EVT3,
EVT_NUM,
}
In this way, I can extend the EventDef system in another header UIEventDef.h by
#include "EventDef.h"
enum UIEventDef {
UIEVT1 = EVT_NUM,
UIEVT2,
UIEVT3,
}
But, there is a limitation that i can not do this in NetEvent.h the same way.
#include "EventDef.h"
enum NetEventDef {
NETEVT1 = EVT_NUM,
NETEVT2, //wrong: this will have the same value as UIEVT2
NETEVT3,
}
Is there a better compile time solution in C++ such as templates that can help ?
The idea of extensible enums is not inherently "bad design". In other languages there is a history of them, even if c++ does not support them directly. There are different kinds of extensibility.
Things that extensible enums would be useful for
error codes
message types
device identification (OIDs are a hierarchical enum like system)
Examples of enum extensibility
Objective Modula Two has enums that are extensible with a class like inheritance.
The Extensible Enum Pattern in Java, which can be implemented in c++.
Java enums are extensible in that extra data and methods can be a part of an enum.
In c++, the typeid operator is essentially a compiler generated enum with attached values.
The kind of extensibility you showed in your sample code does not have an elegant implementation in unaided c++. In fact, as you pointed out, it easily leads to problems.
Think about how you are wanting to use an extensible enum. Perhaps a set/map of immutable singleton objects will meet your needs.
Another way to have extensible enums in c++ is to use a code generator. Every compilation unit that wants to add to an extensible enum, records the ids in its own, separate, .enum file. At build time, before compilation, a script (ie perl, bash, ...) looks for all .enum files, reads them, assigns numeric values to each id, and writes out a header file, which is included like any other.
Why do you want your event enums to be declared like that? What do you gain by having them 'linked' if you will, they way you describe?
I would make them completely independent enums. Secondly, I recommend you not use the old style enums anymore. c++11 is here and available in gcc. You should use enum classes:
enum class EventDef : unsigned { Evt1 = 0, Evt2, Evt3, ... LastEvt }
enum class NetEvtDef : unsigned { NetEvt1 = 0, NetEvt2, NetEvt3, ... NetLastEvt }
If you are switching you can do this:
void doSwitch(EventDef evt_def)
{
switch(evt_def)
{
case EventDef::Evt1
{
// Do something;
break;
}
default:
// Do something;
};
}
void doSwitch(NetEvtDef net_def)
{
switch(net_def)
{
case NetEvtDef::NetEvt1
{
// Do something;
break;
}
default:
// Do something;
};
}
By creating an overloaded function for doSwitch you segregate all your enum types. Having them in separate categories is a benefit not a problem. It provides you the flexibility to deal with each event enum type differently.
Chaining them together as you describe needlessly complicates the problem.
I hope that helps.
I find the following a useful compromise between complexity, features, and type safety. It uses global variables of a custom class that has a default constructor to make initialisation easy. The example below is an extendable set of error codes. You might want to enclose within a name space also (but I typically don't bother).
//
// ErrorCodes.h
// ExtendableEnum
//
// Created by Howard Lovatt on 10/01/2014.
//
#ifndef ErrorCodes_h
#define ErrorCodes_h
#include <string>
class ErrorCodes {
public:
static int nextValue_;
explicit ErrorCodes(std::string const name) : value_{nextValue_++}, name_{name} {}
ErrorCodes() : ErrorCodes(std::to_string(nextValue_)) {}
int value() const { return value_; }
std::string name() const { return name_; }
private:
int const value_;
std::string const name_;
ErrorCodes(const ErrorCodes &);
void operator=(const ErrorCodes &);
};
int ErrorCodes::nextValue_ = 0; // Weird syntax, does not declare a variable but rather initialises an existing one!
ErrorCodes first;
ErrorCodes second;
// ...
#endif
//
// ExtraErrorCodes.h
// ExtendableEnum
//
// Created by Howard Lovatt on 10/01/2014.
//
#ifndef ExtraErrorCodes_h
#define ExtraErrorCodes_h
#include "ErrorCodes.h"
ErrorCodes extra{"Extra"};
#endif
//
// ExtraExtraExtraCodes.h
// ExtendableEnum
//
// Created by Howard Lovatt on 10/01/2014.
//
#ifndef ExtendableEnum_ExtraExtraCodes_h
#define ExtendableEnum_ExtraExtraCodes_h
#include "ErrorCodes.h"
ErrorCodes extraExtra{"ExtraExtra"};
#endif
//
// main.cpp
// ExtendableEnum
//
// Created by Howard Lovatt on 10/01/2014.
//
#include <iostream>
#include "ErrorCodes.h"
#include "ExtraErrorCodes.h"
#include "ExtraExtraErrorCodes.h"
// Need even more error codes
ErrorCodes const localExtra;
int main(int const notUsed, const char *const notUsed2[]) {
std::cout << first.name() << " = " << first.value() << std::endl;
std::cout << second.name() << " = " << second.value() << std::endl;
std::cout << extra.name() << " = " << extra.value() << std::endl;
std::cout << extraExtra.name() << " = " << extraExtra.value() << std::endl;
std::cout << localExtra.name() << " = " << localExtra.value() << std::endl;
return 0;
}
The output is:
0 = 0
1 = 1
Extra = 2
ExtraExtra = 3
4 = 4
If you have multiple compilation units then you need to use a variation on the singleton pattern:
class ECs {
public:
static ErrorCode & first() {
static ErrorCode instance;
return instance;
}
static ErrorCode & second() {
static ErrorCode instance;
return instance;
}
private:
ECs(ECs const&);
void operator=(ECs const&);
};
We can construct an extensible “enum” in C++ as follows:
struct Last {};
struct D
{
using Next = Last;
static const char* name = “D”;
};
struct C
{
using Next = D;
static const char* name = “C”;
};
struct B
{
using Next = C;
static const char* name = “B”;
};
using First = B;
We can iterate thru the above using these constructs:
void Process(const B&)
{
// do something specific for B
cout << “Call me Ishmael” << endl;
}
template <class T>
void Process(const T&)
{
// do something generic
cout << “Call me “ << T::name << endl;
}
template <class T>
struct IterateThru
{
static void iterate()
{
Process(T());
IterateThru<T::Next>::iterate();
}
};
template <>
struct IterateThru<Last>
{
static void iterate()
{
// end iteration
}
};
To iterate through the “enumeration”:
IterateThru<First>::iterate();
To extend the “enumeration”:
struct A
{
using Next = B;
static const char* name = “A”;
}:
using First = A: