Efficient way to define an introspective C++ class hierararchy description ? - c++

I have a C++ class hierarchy defined by inheritance and I store a description of this hierarchy in it that I can later use for introspection. I would like to know if there is a more efficient or cleaner way to define this than the way I currently do it.
Here is a stripped down version of my code
// in header file (hpp)
struct Type
{
Type( const string& n, const Type* p = nullptr ) : name(n), parent(p) {}
const string name;
const Type* parent;
};
class Base
{
public:
static const Type m_type;
virtual const Type& type() const { return m_type; }
};
class Derived : public Base
{
public:
static const Type m_type;
const Type& type() const { return m_type; }
};
// in implementation file (cpp)
const Type Base::m_type( "Base" );
const Type Derived::m_type( "Derived", &Base::m_type );

Not necessarily more efficient but think whether you actually want to require a common base class. An alternative approach uses a global type information registry. Then querying a type’s type information is done via TypeInfo::get(my_variable) or TypeInfo::get(typeid(my_type)).
This has the advantage that it also works with existing types, which just need to be added to this type info registry.
Internally, the registry would use a map from std::type_info to Type or similar. The following is a proof of concept. Unfortunately the code doesn’t compile on either clang or GCC. Based on the error messages, I’m suspecting a bug but I could also be wrong …
struct Type {
std::string name;
std::vector<Type*> parents;
// TODO Extend by fully-qualified name (namespace) etc.
template <typename... T>
Type(std::string&& name, T*... parents)
: name(name), parents{parents...} { }
};
struct TypeInfo {
template <typename T>
static Type const& get(T const&) { return get(typeid(T)); }
template <typename T>
static Type const& get() { return get(typeid(T)); }
static Type const& get(std::type_info const& info) {
auto i = types.find(info);
if (i == types.end())
throw unknown_type_error(info.name());
return i->second;
}
template <typename T>
static void register_type(Type&& type) {
types.insert(std::make_pair(typeid(T), type));
}
typedef std::unordered_map<std::type_info, Type> type_dir_t;
static type_dir_t types;
};
Full code available as gist on github.
Having a common base class for logically unrelated classes is generally frowned upon in C++, although it could be argued that this is similar to CRTP / mixins, in which common base classes are encouraged. So I’d say that there isn’t necessarily anything wrong with the approach if you don’t care for existing types.

Related

Must all code interacting with templated types also use templates?

Must all code interacting with templated classes also use templates?
Imagine
template<T>
class Data {
public:
Data(T value) {
this->value = value;
};
T getValue() {
return value;
};
virtual size_t size() = 0;
private:
T value;
};
There will be specific implementations of size() for several possible T (String, int, etc.).
Note: I could have an abstract class, but then I wouldn't be able to have neither the constructor/getValue, nor virtual methods, because I would have to specify their argument/return value types.
Further imagine that I have function such as
template<T>
size_t getSize(Data<T> value) {
return value.size();
}
Although size() will be different for each different type, the sender (the getSize() method) shouldn't care about T.
So the question is why is it necessary to template the function, and can I avoid it?
Must all code interacting with templated classes also use templates?
Yes. Note that what you have is a class template which is a way to express a family of classes. It does not make a class. You do that by instaniating the template with a type like Data<int> will stamp out a version of Data where T is an int.
why is it necessary to template the function
The reason is that a Data<int> and a Data<double are not the same class. Just like an int and double are different, you get different classes when instatiating the class template with different template parameter. Beacuse of this if you want a function that can deal with anything the class template can produce then that function also needs to be function template so it can stamp out a function for each different Data that is produced.
and can I avoid it
One thing you could do is have Data dervive from a base class and then move size into the base class. Then you could write the function to accept a reference to the base class instead of the class template.
Is that what you are looking for ?
class Base
{
public:
virtual size_t size() = 0;
};
template<typename T>
class Data : public Base
{
public:
Data(T value) {
this->value = value;
};
T getValue() {
return value;
};
size_t size()
{
return this->value.size();
}
private:
T value;
};
size_t getSize(Base& value)
{
return value.size();
}
void test()
{
std::vector<int> vi;
Data<std::vector<int>> d(vi);
getSize(d);
}

CRTP and method returning void *

I use C++ 11. I have a Base class and several derived classes for parsing different configuration files line by line.
template <class T>
class Base
{
public:
virtual ~Base();
bool load_from_file(const QString& str);
virtual void* get_data(const QString& str) const = 0;
private:
QList<QSharedPointer<T> > items_;
};
Each descendant (class Derived: public Base<My_struct>) must provide get_data() implementation.
Each My_struct instance contains information from certain line of a settings file.
For example, imagine a typical file with a list of proxies.
My_struct instances are wrapped in smart pointers in Base class in the load_from_file() method and appended to the items_ member. load_from_file() method casts void* to T* before wrapping.
Is it possible to redesign these classes in order to avoid using void* (and without libraries like boost::any)?
I mean considering CRTP and so on. Usually CRTP examples contain methods of derived classes with void return values (like procedures in Pascal).
Bro! Try to switch to C++14 and use the following snippet as a hint:
template <typename Derived>
struct base
{
template <typename T>
auto f(T x)
{
return static_cast<Derived&>(*this).f_impl(x);
}
auto g()
{
return static_cast<Derived&>(*this).g_impl();
}
};
struct derived : base<derived>
{
bool f_impl(int x)
{
return true;
}
double g_impl()
{
return 4.2;
}
};
This fragment has been taken from here.

What is an appropriate interface for dealing with meta-aspects of classes?

I'm looking for some advice of what would be an appropriate interface for dealing with aspects about classes (that deal with classes), but which are not part of the actual class they are dealing with (meta-aspects). This needs some explanation...
In my specific example I need to implement a custom RTTI system that is a bit more complex than the one offered by C++ (I won't go into why I need that). My base object is FooBase and each child class of this base is associated a FooTypeInfo object.
// Given a base pointer that holds a derived type,
// I need to be able to find the actual type of the
// derived object I'm holding.
FooBase* base = new FooDerived;
// The obvious approach is to use virtual functions...
const FooTypeInfo& info = base->typeinfo();
Using virtual functions to deal with the run-time type of the object doesn't feel right to me. I tend to think of the run-time type of an object as something that goes beyond the scope of the class, and as such it should not be part of its explicit interface. The following interface makes me feel a lot more comfortable...
FooBase* base = new FooDerived;
const FooTypeInfo& info = foo::typeinfo(base);
However, even though the interface is not part of the class, the implementation would still have to use virtual functions, in order for this to work:
class FooBase
{
protected:
virtual const FooTypeInfo& typeinfo() const = 0;
friend const FooTypeInfo& ::foo::typeinfo(const FooBase*);
};
namespace foo
{
const FooTypeInfo& typeinfo(const FooBase* ptr) {
return ptr->typeinfo();
}
}
Do you think I should use this second interface (that feels more appropriate to me) and deal with the slightly more complex implementation, or shoud I just go with the first interface?
#Seth Carnegie
This is a difficult problem if you don't even want derived classes to know about being part of the RTTI ... because you can't really do anything in the FooBase constructor that depends on the runtime type of the class being instantiated (for the same reason you can't call virtual methods in a ctor or dtor).
FooBase is the common base of the hierarchy. I also have a separate CppFoo<> class template that reduces the amount of boilerplate and makes the definition of types easier. There's another PythonFoo class that work with Python derived objects.
template<typename FooClass>
class CppFoo : public FooBase
{
private:
const FooTypeInfo& typeinfo() const {
return ::foo::typeinfo<FooClass>();
}
};
class SpecificFoo : public CppFoo<SpecificFoo>
{
// The class can now be implemented agnostic of the
// RTTI system that works behind the scenes.
};
A few more details about how the system works can be found here:
► https://stackoverflow.com/a/8979111/627005
You can tie dynamic type with static type via typeid keyword and use returned std::type_info objects as means of identification. Furthermore, if you apply typeid on a separate class created specially for the purpose, it will be totally non-intrusive for the classes you are interesed in, althought their names still have to be known in advance. It is important that typeid is applied on a type which supports dynamic polymorphism - it has to have some virtual function.
Here is example:
#include <typeinfo>
#include <cstdio>
class Base;
class Derived;
template <typename T> class sensor { virtual ~sensor(); };
extern const std::type_info& base = typeid(sensor<Base>);
extern const std::type_info& derived = typeid(sensor<Derived>);
template <const std::type_info* Type> struct type
{
static const char* name;
static void stuff();
};
template <const std::type_info* Type> const char* type<Type>::name = Type->name();
template<> void type<&base>::stuff()
{
std::puts("I know about Base");
}
template<> void type<&derived>::stuff()
{
std::puts("I know about Derived");
}
int main()
{
std::puts(type<&base>::name);
type<&base>::stuff();
std::puts(type<&derived>::name);
type<&derived>::stuff();
}
Needless to say, since std::type_info are proper objects and they are unique and ordered, you can manage them in a collection and thus erase type queried from the interface:
template <typename T> struct sensor {virtual ~sensor() {}};
struct type
{
const std::type_info& info;
template <typename T>
explicit type(sensor<T> t) : info(typeid(t))
{};
};
bool operator<(const type& lh, const type& rh)
{
return lh.info.before(rh.info);
}
int main()
{
std::set<type> t;
t.insert(type(sensor<Base>()));
t.insert(type(sensor<Derived>()));
for (std::set<type>::iterator i = t.begin(); i != t.end(); ++i)
std::puts(i->info.name());
}
Of course you can mix and match both, as you see fit.
Two limitations:
there is no actual introspection here . You can add it to template struct sensor via clever metaprogramming, it's very wide subject (and mind bending, sometimes).
names of all types you want to support have to be known in advance.
One possible variation is adding RTTI "framework hook" such as static const sensor<Myclass> rtti_MyClass; to implementation files where class names are already known and let the constructor do the work. They would also have to be complete types at this point to enable introspection in sensor.

C++ Virtual template method

I have an abstract class (I know that it will not compile this way, but it's for comprehension of what I want to do) :
class AbstractComputation {
public:
template <class T> virtual void setData(std::string id, T data);
template <class T> virtual T getData(std::string id);
};
class Computation : public AbstractComputation {
public:
template <class T> void setData(std::string id, T data);
template <class T> T getData(std::string id, T data);
};
So when I call setData<double>("foodouble", data) I want the double identified by foodouble (internal mechanism which is not the main concern here) to be set to the double data.
So how to do that?
I think that there may be a mean by typing something like virtual void setData<double>(std::string id, double data) but I don't know how to do it.
The problem is that you cannot mix static time polymorphism (templates) with runtime polymorphism easily. The reason for the language disallowing the particular construct in your example is that there are potentially infinite different types that could be instantiating your template member function, and that in turn means that the compiler would have to generate code to dynamically dispatch those many types, which is infeasible.
There are different things that can be done here to get around the limitation, basically either take away the static or the dynamic polymorphism. Removing dynamic polymorphism from the equation could be done by providing a type that is not derived from, to store the <key,value> mappings, and then offering the template that resolves that only at the base level:
class AbstractComputation {
public:
template <typename T>
void setData( std::string const & id, T value ) {
m_store.setData( id, value );
}
template <typename T>
T getData( std::string const & id ) const {
return m_store.getData<T>( id );
}
protected:
ValueStore m_store;
};
Now deriving classes can access the ValueStore from the base and there is no need for polymorphism. (This can also be done by implementing the functionality directly in AbstractComputation but it probably makes sense to separate concerns)
The other option is to maintain runtime polymorphism, but remove static polymorphism. This can be done by performing type erasure on the base class and then dispatching to the appropriate (non-templated) function that takes the type-erased arguments. The simplest version of this is just using boost::any:
class AbstractComputation {
public:
template <typename T>
void setData( std::string const & id, T value ) {
setDataImpl( id, boost::any( value ) );
}
template <typename T>
T getData( std::string const & id ) const {
boost::any res = getDataImpl( id );
return boost::any_cast<T>( res );
}
protected:
virtual void setDataImpl( std::string const & id, boost::any const & value ) = 0;
virtual boost::any getDataImpl( std::string const & id ) const = 0;
};
How type erasure is implemented under the hood is interesting, but out of the scope here, the important part is that a boost::any is a concrete (non-templated) type that can store any type internally by using type erasure on the arguments, and at the same time allows for type-safe retrieval of the data.
In some cases it may be enough to move the templating from method level to class level, e.g.:
#include <iostream>
template<typename T>
class AbstractComputation {
public:
virtual void setData(std::string id, T data)
{
std::cout << "base" << std::endl;
}
};
template<typename T>
class Computation : public AbstractComputation<T> {
public:
virtual void setData(std::string id, T data)
{
std::cout << "derived" << std::endl;
}
};
int main()
{
AbstractComputation<int> *x = new Computation<int>();
x->setData("1", -1);
delete x;
return 0;
}
You can probably use boost::any in your case.
virtual void setData(std::string id, boost::any data);
It is a wrapper that can encapsulate almost anything.
More info on a similar topic in this answer.
First, you cannot have virtual template functions. As templates are resolved at compile time, virtual will not work, as the compiler would not know which template to pick. See here, for more info about this.
If you know list of possible types in advance, preprocessor may help:
#define MY_CLASSES MYTYPE(int) MYTYPE(float) MYTYPE(double)
class AbstractComputation {
public:
# define MYTYPE(T) virtual void setData(std::string id, T data)=0;\
virtual void getData(std::string id, T& dst_data)=0;
MY_CLASSES
# undef MYTYPE
};
class Computation : public AbstractComputation {
public:
# define MYTYPE(T) virtual void setData(std::string id, T data){std::cout<<"writing: "<<data<<std::endl;}\
virtual void getData(std::string id, T& dst_data){dst_data=0;/*put your actual implementation here*/}
MY_CLASSES
# undef MYTYPE
};
If you don't know a complete list of possible types, perhaps, your problem is unresolvable. Type erasure, as mentioned by others, may also help.. but not in all circumstances.
Use boost::any to accept the datum, and then when you actually set, grab the correct type from it.

How to use policy-templates if the types of two templates are linked?

I'm currently writing a class which allows getting and setting interal program options and it should be quite flexible and easy to use.
Specifically, an option is identified by an enum type and a value type, which have a one-on-one relationship. For example, an enum IntType will contains options which have an int type.
I had in mind the following code, but have no idea how to get it working or whether I'm trying to use templates in a way i shouldn't.
enum IntType {OPTION1, OPTION2}
enum StringType { OPTION3, OPTION4}
template<class T, class T2>
class Policy{
public:
T2 getValue(const T& a);
void setValue(const std::string& name, const T2& a);
...
}
class A: public Policy<IntType, int>, public Policy<Stringtype, std::string>, ...{
...
}
Each enum constant has one associated string representation, which is constant, but options are also taken as string input into the program, so I have to be able to deduce from a string which option I should change.
But obviously, this code cannot be used to directly call set or get values without qualifying its full template specialization. So
A* a = ...
a->setValue("intoption", 5);
will not work.
Any pointers on what I should use to get this working?
A partial answer on how to derive at compile time that OPTION1 maps to int and IntType, ... would also be great.
Thanks in advance,
Broes
It is not necessary to pass both the Enum and the type. You can deduce the enum value from the type itself thanks to a traits class:
template <typename T>
struct PolicyTraits;
template <>
struct PolicyTraits<int> { static Enum const value = IntType; }
// ... and so on ...
Your selection is obviously a bit more difficult. For templates to work correctly you need selection based on compile constants, be they constants or types. This requires the names of your options to be constants.
A revised implementation would thus be:
template<class Name, class Type>
class Policy{
public:
Type getValue(Name);
void setValue(Name, Type const&);
...
}
This can be used as:
struct IntOption {};
class A: public Policy<IntOption, int> {};
int main() {
A a;
a.setValue(IntOption(), 3);
}
Also, you might be interested in looking up How Boost does it and perhaps use their library.
Since you are filling the data at runtime, templates are not viable for this design. Runtime polymorphism with virtual function will be a good choice. For example,
class Options; // Say this is the class of interest
class DataType {
public:
virtual Options& getOptions () = 0;
};
class IntType : public DataType {
public:
Options& getOptions (); // implement for 'int' type
};
class StringType : public DataType {
public:
Options& getOptions (); // implement for 'std::string' type
};
Now, class A should contain a pointer to DataType;
class A {
DataType *pData;
public:
void setValue (DataType *p) { pData = p; }
...
};
Usage:
A *a = ...;
a->setValue(new IntType); // take care of heap allocation / stack allocation