ways to query template specializations at run-time / avoiding the big switch - c++

I have a enum type:
enum class MyEnumType { A , B , C };
and i want to map these enums to description attributes; i like this approach a lot:
template <typename T>
struct MyEnumTypeDescription
{
inline const char* get() { static_assert("description not implemented for this type"); };
};
template<>
const char* MyEnumTypeDescription<MyEnumType::A>::get() { return "A"; }
template<>
const char* MyEnumTypeDescription<MyEnumType::B>::get() { return "B"; }
....
a bit verbose but not that bad, right?
Now, the part that is cumbersome is when i want to get a description from a enumerator at run-time, it means i need to create a big-switch function
const char* getDescriptionFromEnumerator( MyEnumType t )
{
case MyEnumType::A:
return MyEnumTypeDescription<MyEnumType::A>::get();
.....
}
is there some metaprogramming (template or macro) magic that would help me avoid all this boilerplate and error-prone coding?

I would suggest to map it to an array:
enum MyEnumType { A , B , C };
const char *pEnumDescription[] = { "A", "B", "C" };
And based on index you can get the type at runtime.
const char* getDescriptionFromEnumerator(MyEnumType t)
{
return pEnumDescription[t]; // just one statement instead of switch/case
}

Related

Reading in each data member of an unspecified struct from XML

I have some structs with varying types and amounts of data members:
struct Foo
{
int a;
float b;
char c;
}
struct Bar
{
std::string a;
int b;
}
struct Baz
{
char a;
}
I want to fill these data members with values contained in an external file. Is there a general solution such that if I later add a new struct with different data members, I won't have to alter my code that's reading in the data? I'd prefer to keep any functionality independent of these structs, but my best idea at the moment is a polymorphic solution where each struct has a static method responsible for reading in its data.
C++ as of now doesn't have a way to reflect the content of a struct. This means that there is no truly generic way to read into any given struct (neither by name nor by index). However you might create some kind of meta-description which might result in less overhead than to rewrite the XML deserialization for each structure.
Such a meta-description could look like (requires C++17):
enum FieldType { String, Int, Float, Char };
struct AbstractField
{
FieldType const type;
const char * const name;
AbstractField(FieldType type, const char *name) : type(type), name(name) {}
virtual ~AbstractField() {}
virtual bool setValue(std::any & dest, const std::any & value) const = 0;
}
template <typename Struct, typename Type>
struct Field : public AbstractField
{
Type Struct::*const fieldPtr;
Field(FieldType type, const char *name, Type Struct::*fieldPtr)
: AbstractField(type, name), fieldPtr(fieldPtr)
{}
bool setValue(std::any & dest, const std::any & value) const override
{
Struct *realDest = std::any_cast<Struct>(& dest);
const Type *realValue = std::any_cast<Type>(& value);
if (realDest != nullptr && realValue != nullptr) {
realDest->*fieldPtr = *realValue;
return true;
}
return false;
}
}
// The following has to be redone for each structure
static const std::vector<const AbstractField *> metaFoo = {
new Field<Foo, int>(Int, "a", & Foo::a)),
new Field<Foo, float>(Float, "b", & Foo::b)),
new Field<Foo, char>(Char, "c", & Foo:c))
};
There could be added some extra logic to get this even fancier (type_id instead of the enum, templated functions that only take the name and the member pointer to create the Field instance, abstract factories for the individual structs, etc).
The reader could then set a value in the structure like this
std::any parseValue(const std::string & value, FieldType type);
bool setField(std::any &dest, const std::vector<const AbstractField*> &meta,
const std::string & fieldName, const std::string & value)
{
for (auto field : meta) {
if (field->name == fieldName) {
std::any value = parseValue(value, field->type);
return field->setValue(dest, value);
}
}
return false;
}
When combined with abstract factories for the structs (similar to what I've done for the fields) this allows to instanciate a whole tree of structures just from the meta-description.

How to cast enums?

I have a third-party unscoped enum (that I can't modify) that I'd really like to cast to my own scoped enum. How can I provide something like a conversion operator?
What I'd like to do is something like this:
#include <iostream>
enum ThirdPartyLetter {
A=4,
B=5
};
enum class MyNumber {
ONE=1,
TWO=2
// This doesn't compile, of course
/*Number(const ThirdPartyLetter& rhs) {
if(rhs == ThirdPartyLetter::A) {
return ONE;
}
else {
return TWO;
}
}*/
};
int main() {
ThirdPartyLetter letter = ThirdPartyLetter::A;
MyNumber number = static_cast<MyNumber>(letter);
// Without the cast, this prints 4 (an invalid enum value!)
std::cout << int(number) << std::endl;
}
Is there a way to provide some kind of casting from ThirdPartyNumber to MyNumber?
An idiomatic way to do that at compile-time in C++ is using traits.
As an example:
enum Foo { ONE, TWO };
enum Bar { THREE, FOUR };
template<Foo> struct conv;
template<> struct conv<Foo::ONE> { static constexpr Bar value = Bar::THREE; };
template<> struct conv<Foo::TWO> { static constexpr Bar value = Bar::FOUR; };
If you want to do that at runtime, maybe a switch is well suited.
Anyway, you can still use traits to centralize your conversion logic and do something like this:
Bar get(Foo choice) {
switch(choice) {
case Foo::ONE:
return conv<ONE>::value;
case Foo::TWO:
return conv<TWO>::value;
}
}

Template substitution for function names

I'm using a third party C++ library which has a json parsing class that has
different functions like this:
GetInt
GetBool
GetString
GetDouble
I'd like to write a utility function that can access this class. I'm thinking of something like this:
class <template T>
class MyClass {
static T getValue(ThirdPartyClass someObj, const string &key) {
if(someObj[key].IsDouble())
return someObj[key].GetDouble();
else if (someObj[key].IsString())
return someObj[key].GetString();
// ... (for other types)
}
}
The caller of this class will hold the correct return type.
However this is ugly. Is there any way (using macro substitution for example) I can avoid the if conditions? The third party class has IsXXTypeXX and corresponding GetXXTypeXX functions (where XXTypeXX is Int, Double,String or Bool).
I know the return type when I call the function for eg:
int i = getValue(someObj, "intKey");
string s = getValue(someObj, "strKey");
So I dont need the if conditions at all. Ideally I would look to have something so
I would be able to do this:
int i = MyClass<int>::getValue(someObj, "intKey");
string s = MyClass<string>::getValue(someObj, "strKey");
Why not just write a bunch of static Get functions (GetInt/GetDouble...) that validates the input, returns the appropriate type result and throws an exception if it isn't that type?
Technically you can achieve the public interface that you've outlined there but that would involve very ugly looking template specialization.
It would probably be better if you just had a bunch of static functions instead. Here is what template specialization would look like:
template <typename T> class MyClass {
static T getValue(ThirdPartyClass someObj, const string &key) {
// handle types that you didn't specialize for
}
};
template <> class MyClass <string> {
static string getValue(ThirdPartyClass someObj, const string &key) {
return someObj[key].GetString();
}
};
template <> class MyClass <int> {
static int getValue(ThirdPartyClass someObj, const string &key) {
return someObj[key].GetInt();
}
};
//..
Skeleton key for software engineering: add an intermediate layer.
#include <string>
#include <cassert>
using std::string;
class Proxy {
public:
enum Type {
Int,
Bool,
String,
Double
};
Type type;
int i;
bool b;
string s;
double d;
operator int() const {
assert(type == Int);
return i;
}
operator bool() const {
assert(type == Bool);
return b;
}
operator string() const {
assert(type == String);
return s;
}
operator double() const {
assert(type == Double);
return d;
}
Proxy(int i) : type(Int), i(i) {}
Proxy(bool b) : type(Bool), b(b) {}
Proxy(string s) : type(String), s(s) {}
Proxy(double d) : type(Double), d(d) {}
}; // class Proxy
Proxy getValue(ThirdPartyClass someObj, const string &key) {
if (someObj[key].IsDouble())
return someObj[key].GetDouble();
else if (someObj[key].IsString())
return someObj[key].GetString();
//... (for other types)
}
int main() {
int i = getValue(someObj, "intKey"); // if type does not match, a exception will be thrown.
string s = getValue(someObj, "strKey");
}
The code you showed won't compile. You can't in the same function return a double, a string, and an int. What you'd have to do it specialize for each return type, and then call only the function for that type:
template <>
class MyClass<int> getValue(ThirdPartyClass someObj, const string& key) {
if(someOjb[key].IsInt()) return someObj[key].GetInt();
else { /* Maybe throw an exception */ }
};
and repeat for each type.
Now, you're probably thinking, "this is silly, how come I have to specialize each type?" That's because your JSON library is using type erasure, so you have to check the type at runtime. The only way to save yourself the work is if the library provides a templated get.
If you want, you could create a macro to stamp these instantiations out. It would take advantage of the # (stringification) and ## (concatenation) features of the preprocessor. It'll probably be clearer to just write them out.

Is it possible to have conditional declaration of methods and variables in templated classes?

I am trying to make a class that can have functions and members controlled by a template argument. I am thinking of something like this.
template<int control>
class ControlledDeclaration
{
public:
if(1 == control)
int Get() { return 0; }
else if(2 == control)
char* Get() { return "get"; }
else if (3 == control)
bool Get() { return true; }
};
void test_template()
{
ControlledDeclaration<1> c_int;
ControlledDeclaration<2> tx_int;
ControlledDeclaration<3> b_int;
}
If possible, how to do it?
The approach I would use is along the lines of specializing the details in a traits class and provide the interface using the template. In this trivial example there isn't much benefit of using traits rather than specializing the actual type but in general customizing the few points of variations is easier using traits than specializations.
template <int> struct ControlDeclarationTraits;
template <>
struct ControlDeclarationTraits<1> {
typedef int type;
static int value() { return 0; };
};
template <>
struct ControlDeclarationTraits<2> {
typedef char const* type;
static char const* value() { return "get"; }
};
template <>
struct ControlDeclarationTraits<3> {
typedef bool type;
static bool value() { return true; }
};
template<int control>
class ControlledDeclaration
{
public:
typename ControlDeclarationTraits<control>::type Get() {
return ControlDeclarationTraits<control>::value();
}
};
BTW, the type of string literals is char const[n] (for a suitable n) and not char[n], i.e., you can't really use a string literal to initialize a char*. It does work because it was deemed necessary to support existing code to assign string literals to char* but it is actually a lie: trying to assign a value to any of the values causes undefined behavior. Making the pointer const makes it obvious that the content isn't meant to be modified.
Have a look at boost::enable_if, that does exactly what you want.

Dynamically define a function return type

I have a Message class that is able to pack its payload to binary and unpack it back. Like:
PayloadA p;
msg->Unpack(&p);
where PayloadA is a class.
The problem is that I have a bunch of payloads, so I need giant if or switch statement:
if (msg->PayloadType() == kPayloadTypeA)
{
PayloadA p;
msg->Unpack(&p); // void Unpack(IPayload *);
// do something with payload ...
}
else if ...
I want to write a helper function that unpacks payloads. But what would be the type of this function? Something like:
PayloadType UnpackPayload(IMessage *msg) { ... }
where PayloadType is a typedef of a proper payload class. I know it is impossible but I looking for solutions like this. Any ideas?
Thanks.
I would split one level higher to avoid the problem entirely:
#include <map>
#include <functional>
...
std::map<int, std::function<void()> _actions;
...
// In some init section
_actions[kPayloadA] = [](IMessage* msg) {
PayloadA p;
msg->Unpack(&p);
// do something with payload ...
};
// repeat for all payloads
...
// decoding function
DecodeMsg(IMessage* msg) {
_actions[id](msg);
}
To further reduce the code size, try to make Unpack a function template (possible easily only if it's not virtual, if it is you can try to add one level of indirection so that it isn't ;):
class Message {
template <class Payload>
Payload Unpack() { ... }
};
auto p = msg->Unpack<PayloadA>();
// do something with payload ...
EDIT
Now let's see how we can avoid writing the long list of _actions[kPayloadN]. This is highly non trivial.
First you need a helper to run code during the static initialization (i.e. before main):
template <class T>
class Registrable
{
struct Registrar
{
Registrar()
{
T::Init();
}
};
static Registrar R;
template <Registrar& r>
struct Force{ };
static Force<R> F; // Required to force all compilers to instantiate R
// it won't be done without this
};
template <class T>
typename Registrable<T>::Registrar Registrable<T>::R;
Now we need to define our actual registration logic:
typedef map<int, function<void()> PayloadActionsT;
inline PayloadActionsT& GetActions() // you may move this to a CPP
{
static PayloadActionsT all;
return all;
}
Then we factor in the parsing code:
template <class Payload>
struct BasePayload : Registrable<BasePayload>
{
static void Init()
{
GetActions()[Payload::Id] = [](IMessage* msg) {
auto p = msg->Unpack<Payload>();
p.Action();
}
}
};
Then we define all the payloads one by one
struct PayloadA : BasePayload<PayloadA>
{
static const int Id = /* something unique */;
void Action()
{ /* what to do with this payload */ }
}
Finally we parse the incoming messages:
void DecodeMessage(IMessage* msg)
{
static const auto& actions = GetActions();
actions[msg->GetPayloadType]();
}
How about a Factory Method that creates a payload according to the type, combined with a payload constructor for each payload type, taking a message as a parameter?
There's no avoiding the switch (or some similar construct), but at least it's straightforward and the construction code is separate from the switch.
Example:
class PayloadA : public Payload
{
public:
PayloadA(const &Message m) {...} // unpacks from m
};
class PayloadB : public Payload
{
public:
PayloadB(const &Message m) {...} // as above
};
Payload * UnpackFromMessage(const Message &m)
{
switch (m.PayloadType) :
case TypeA : return new PayloadA(m);
case TypeB : return new PayloadB(m);
... etc...
}
I seen this solved with unions. The first member of the union is the type of packet contained.
Examples here: What is a union?
An important question is how the payloads differ, and how they are the same. A system whereby you produce objects of a type determined by the payload, then interact with them via a virtual interface that is common to all types of payload, is reasonable in some cases.
Another option assuming you have a finite and fixed list of types of payload, returning a boost::variant is relatively easy. Then to process it, call apply_visitor with a functor that accepts every type in the variant.
If you only want to handle one type of payload differently, a "call and run the lambda if and only if the type matches T" function isn't that hard to write this way.
So you can get syntax like this:
struct State;
struct HandlePayload
{
typedef void return_type;
State* s;
HandlePayload(State* s_):s(s_) {}
void operator()( int const& payload ) const {
// handle int here
}
void operator()( std::shared_ptr<bob> const& payload ) const {
// handle bob ptrs here
}
template<typename T>
void operator()( T const& payload ) const {
// other types, maybe ignore them
}
}
which is cute and all, but you'll note it is quite indirect. However, you'll also note that you can write template code with a generic type T above to handle the payload, and use stuff like traits classes for some situations, or explicit specialization for others.
If you expect the payload to be one particular kind, and only want to do some special work in that case, writing a single-type handler on a boost::variant is easy.
template<typename T, typename Func>
struct Helper {
typedef bool return_type;
Func f;
Helper(Func f_):f(f_) {}
bool operator()(T const& t) {f(t); return true; }
template<typename U>
bool operator()(U const& u) { return false; }
};
template<typename T, typename Variant, typename Func>
bool ApplyFunc( Variant const& v, Func f )
{
return boost::apply_visitor( Helper<T, Func>(f), v );
}
which will call f on a variant v but only on the type T in the Variant, returning true iff the type is matched.
Using this, you can do stuff like:
boost::variant<int, double> v = 1.0;
boost::variant<int, double> v2 = int(1);
ApplyFunc<double>( v, [&](double d) { std::cout << "Double is " << d << "\n"; } );
ApplyFunc<double>( v2, [&](double d) { std::cout << "code is not run\n"; } );
ApplyFunc<int>( v2, [&](int i) { std::cout << "code is run\n"; } );
or some such variant.
One good solution is a common base class + all payloads inheriting from that class:
class PayLoadBase {
virtual char get_ch(int i) const=0;
virtual int num_chs() const=0;
};
And then the unpack would look like this:
class Unpacker {
public:
PayLoadBase &Unpack(IMessage *msg) {
switch(msg->PayLoadType()) {
case A: a = *msg; return a;
case B: b = *msg; return b;
...
}
}
private:
PayLoadA a;
PayLoadB b;
PayLoadC c;
};
You can make the function return a void *. A void pointer can be cast to any other type.