I'm currently trying to build a class hierarchy automatically by using C++ templates. The final result is a message handler class that provides handler functions for all possible messages, given in a typelist.
However when inheriting from that class hierarchy and trying to implement the handler function to actually do the application code for some types only, C++ isn't calling the function from the base class.
The following is a minimal and complete example what I'm trying to achieve. It doesn't compile because C++ complains about not finding an overload for handle( const B& ).
#include <iostream>
#include <typeinfo>
// Typelist.
struct None {};
template <class H, class T = None>
struct Typelist {
typedef H Head;
typedef T Tail;
};
template <class TL>
struct Handler : public Handler<typename TL::Tail> {
using Handler<typename TL::Tail>::handle;
virtual void handle( const typename TL::Head& obj ) {
std::cout << "Not handled! " << typeid( typename TL::Head ).name() << std::endl;
}
};
template <>
struct Handler<None> {
virtual void handle() {}
};
struct A {};
struct B {};
typedef Typelist<A, Typelist<B> > MsgList;
struct MyHandler : Handler<MsgList> {
void handle( const A& a ) {
std::cout << "A!" << std::endl;
}
};
int main() {
MyHandler handler;
A a;
B b;
handler.handle( a );
handler.handle( b );
}
You need to use handle from you Handle<MsgList> in your MyHandler class
using Handler<MsgList>::handle;
Right now it is hidden and do not overload the name handle in MyHandler class. And taking into account the code of the Handler, you know this :-)
Related
I have two interfaces that I want to use with CRTP for static polymorphism. One of them contains a function whose types in the signature are implementation-dependent.
This problem looks like what has been asked here without solution. The solution I came up with includes an additional templated structure defining the type. This template is then specialized for the implementation avoiding the "invalid use of incomplete type" error.
Here my code
#include <iostream>
#include <memory>
template<class impl1>
struct Interface1 {
double foo() { return static_cast<impl1*>(this)->fooimpl();}
};
template<class impl1, class impl2>
struct typeHelp;
template<class impl1, class impl2>
struct Interface2 {
void bar(typename typeHelp<impl1,impl2>::type value) {
static_cast<impl2*>(this)->barimpl(value);
}
};
//Implementation2 pre declaration
template<class impl1>
struct Implementation2;
//Partial specialization of templated typeHelp
template<class impl1>
struct typeHelp<impl1, Implementation2<impl1>> {
using type = int;
};
//Implementation2
template<class impl1>
struct Implementation2 : public Interface2<impl1, Implementation2<impl1>> {
std::shared_ptr<Interface1<impl1>> imp1;
void barimpl(typename typeHelp<impl1,Implementation2>::type value) {
std::cout << imp1->foo() << " " << value << std::endl;
}
};
//Implementation1
struct Implementation1 : public Interface1<Implementation1> {
double fooimpl() {return 0.;}
};
int main()
{
Implementation2<Implementation1> obj;
obj.imp1 = std::make_shared<Implementation1>();
obj.bar(4);
}
What I don't like in this code is that Interface2 and typeHelp depend on template parameter impl1. This works for my particular case, where Implementation2 is templated with respect to impl1 but it wouldn't if Implementation2 weren't. I wonder if there is a more general and elegant solution to this problem.
My bad; a little bit more of search and I would have found the answer. On this link, Andy G points out that it is possible to specialize a class template with a templated class. The result is more clean than before
#include <iostream>
#include <memory>
//Interface1.hpp
template<class impl1>
struct Interface1 {
double foo() { return static_cast<impl1*>(this)->fooimpl();}
};
//Interface2.hpp
template<class impl2>
struct typeHelp;
template<class impl2>
struct Interface2 {
void bar(typename typeHelp<impl2>::type value) {
static_cast<impl2*>(this)->barimpl(value);
}
};
//Implementation2.hpp
template<class impl1>
struct Implementation2;
//specialization of typeHelp with templated class
template<class impl1>
struct typeHelp<Implementation2<impl1>> {
using type = int;
};
//Actual implementation of Implementation2
template<class impl1>
struct Implementation2 : public Interface2<Implementation2<impl1>> {
std::shared_ptr<Interface1<impl1>> imp1;
void barimpl(typename typeHelp<Implementation2<impl1>>::type value) {
std::cout << imp1->foo() << " " << value << std::endl;
}
};
//Implementation1.hpp
struct Implementation1 : public Interface1<Implementation1> {
double fooimpl() {return 0.;}
};
//Main.hpp
int main()
{
Implementation2<Implementation1> obj;
obj.imp1 = std::make_shared<Implementation1>();
obj.bar(4);
}
I want to write class that extends multiple classes by (CRTP).
I can only get Extension<Base<Extension>> my_object; to work.
The api that I want is: Extension<Base> my_object;
How to make this api work?
Thanks.
Test (code is also at godbolt.org):
#include <iostream>
template <template<typename...> class Extension>
class Base1 : public Extension<Base1<Extension>> {
public:
static void beep() { std::cout << "Base1 "; }
};
template <class Plugin>
class Extension1 {
public:
Extension1() : plugin_(static_cast<Plugin*>(this)) {}
void beep() {
plugin_->beep();
std::cout << "Extension1\n";
}
private:
Plugin* plugin_;
};
template <template<typename...> class Plugin>
class Extension2 {
public:
Extension2() : plugin_(static_cast<Plugin<Extension2>*>(this)) {}
void beep() {
plugin_->beep();
std::cout << "Extension2\n";
}
private:
Plugin<Extension2>* plugin_;
};
int main() {
// This works.
Extension1<Base1<Extension1>>b;
b.beep();
// This doesn't work.
Extension2<Base1> c;
c.beep();
return 0;
}
One problem is that the template parameter to Extension2 does not match the signature that Base1 has. Another is that Extension2 does not match the parameter type expected by Base1.
If you change the definition of Extension2 to propertly accept Base1, it itself is still not a candidate to be passed to Base1. You can workaround that with an inner template class that does match what Base1 expects. This inner class would look a lot like Extension1.
template <template<template<typename...> class> class Plugin>
class Extension2 {
template <class P>
struct Inner {
Inner () : plugin_(static_cast<P *>(this)) {}
void beep() { plugin_->beep(); }
private:
P* plugin_;
};
public:
Extension2() {}
void beep() {
plugin_.beep();
std::cout << "Extension2\n";
}
private:
Inner<Plugin<Inner>> plugin_;
};
I would like to add support for protobuf events to my existing event queue.
I wrote a proof-of-concept (see below), which seemed to work fine at first. Unfortunately, compilation aborts when accessing inherited data members. Accessing inherited function members works just fine. Following classes are declared:
Abstract class SubscriptionHolderBase: This is the interface base class
Abstract class SubscriptionHolderCommon: Is supposed to hold the common members of the following two classes.
Depending on the type of the event to subscribe, the compiler shall automatically choose one of the following classes to instantiate:
Template class SubscriptionHolder, specialized for normal events.
Templace class SubscriptionHolder, spezialized for all other (i.e. protobuf) events.
For some reason, SubscriptionHolder seems to inherit the function member of SubscriptionHolderCommon just fine, but when trying to access the data member _member_var (inherited from the same class), following error message is produced:
error: ‘_member_var’ was not declared in this scope
Can someone explain the reason?
My proof-of-concept code:
When commenting all 3 occurences of _member_var, it is doing just fine.
You can compile and let it run online here.
#include <type_traits>
#include <iostream>
class ProtobufEvent {
};
class Proto2 : public ProtobufEvent {
};
class Event {
public:
virtual ~Event(){};
};
class SubscriptionHolderBase {
public:
virtual bool dispatch(Event* event) = 0;
virtual void handle() = 0;
};
template<typename EventType>
class SubscriptionHolderCommon : public SubscriptionHolderBase {
public:
void handle() {
std::cout << "Member function of unspecialized common base class called." << std::endl;
}
protected:
bool _member_var;
};
template<typename EventType, typename Enable = void>
class SubscriptionHolder;
template<typename EventType>
class SubscriptionHolder<EventType, typename std::enable_if<std::is_convertible<EventType*, ProtobufEvent*>::value>::type> : public SubscriptionHolderCommon<EventType> {
public:
virtual bool dispatch(Event* event);
};
template<typename EventType>
class SubscriptionHolder<EventType, typename std::enable_if<!std::is_convertible<EventType*, ProtobufEvent*>::value>::type> : public SubscriptionHolderCommon<EventType> {
public:
virtual bool dispatch(Event* event);
};
template<typename EventType>
bool SubscriptionHolder<EventType, typename std::enable_if<std::is_convertible<EventType*, ProtobufEvent*>::value>::type>::dispatch(Event* event) {
std::cout << "Member function of specialized class for protobuf event called." << std::endl;
_member_var = true;
return false;
}
template<typename EventType>
bool SubscriptionHolder<EventType, typename std::enable_if<!std::is_convertible<EventType*, ProtobufEvent*>::value>::type>::dispatch(Event* event) {
std::cout << "Member function of specialized class for standard event called." << std::endl;
_member_var = true;
return false;
}
int main() {
Event* e = nullptr;
SubscriptionHolderBase* ptr;
SubscriptionHolder<Event> s_e;
ptr = &s_e;
ptr->handle();
ptr->dispatch(e);
std::cout << std::endl;
SubscriptionHolder<ProtobufEvent> s_p;
ptr = &s_p;
ptr->handle();
ptr->dispatch(e);
std::cout << std::endl;
SubscriptionHolder<Proto2> s_p2;
ptr = &s_p2;
ptr->handle();
ptr->dispatch(e);
std::cout << std::endl;
}
I want to find out what is the parent of the type class T in a template function, suppose I've the following classes:
class A{
...
}
class B: public A{
...
}
class C: public B{
...
}
template<typename T>
size_t getBaseHashCode()
{
return typeid(base_of(T)).hashcode();
}
int main()
{
A a;
C c;
size_t size = getBaseHashCode<C>();// must return hashcode of class B
}
is there anyway to find parent of type T and implement base_of function?
Edit:
indeed what I want to do is:
I've factory class which creates objects for me:
template <typename B>
class Factory{
public:
template <typename D>
void registerType(std::string name)
{
static_assert(std::is_base_of<B, D>::value, "class doesn't derive from the base");
table_[name] = &createFunc<D>;
}
B* create(std::string name)
{
const auto it = table_.find(name);
if(it != table_.end())
return it->second();
FILE_LOG(logERROR) << "unidentified option, acceptable options are:";
for(auto const &m : list())
FILE_LOG(logERROR) << '\t' << m;
return nullptr;
}
std::vector<std::string> list()
{
std::vector<std::string> lst;
for(auto const &iter : table_)
lst.push_back(iter.first);
return lst;
}
private:
template<typename D>
static B* createFunc()
{
return new D();
}
typedef B* (*PCreateFunc)();
std::map<std::string, PCreateFunc> table_;
};
in the registerType function I want to set some properties of type D or it's parent and then in the create function, I want to create objects based on that.
You might also consider using some parent wrappers to automatize typedefing:
#include <type_traits>
#include <typeinfo>
#include <iostream>
template <class P>
struct base: P {
using base_type = P;
};
struct A{ };
struct B: base<A>{ };
struct C: base<B>{ };
template <class T>
auto base_of(T) -> typename T::base_type;
template <class T>
using base_of_t = decltype(base_of(std::declval<T>()));
int main() {
std::cout << typeid(base_of_t<C>).name() << std::endl;
}
Output:
1B
Output of c++filt -t 1B:
B
[live demo]
Note it still does not deal with multiple inheritance
You can use a couple of functions declarations that you don't have to define.
It follows a minimal, working example:
#include<utility>
#include<typeinfo>
#include<iostream>
class A{};
class B: public A{};
class C: public B{};
B base_of(const C &);
A base_of(const B &);
template<typename T>
void getBaseHashCode() {
std::cout << typeid(decltype(base_of(std::declval<T>()))).name() << std::endl;
}
int main() {
getBaseHashCode<B>();
getBaseHashCode<C>();
}
It exploits the fact that, in this case, you have exact matches during the invokations. It's quite weak a solution, but works with the example code in the question.
That said, I agree on the fact that the whole question looks like an XY-problem.
EDIT
As mentioned by #Jarod42 in the comments, a more idiomatic (and verbose) way would be by using traits.
It follows a minimal, working example:
#include<typeinfo>
#include<iostream>
class A{};
class B: public A{};
class C: public B{};
template<typename> struct base_of;
template<> struct base_of<B> { using type = A; };
template<> struct base_of<C> { using type = B; };
template<typename T>
void getBaseHashCode() {
std::cout << typeid(typename base_of<T>::type).name() << std::endl;
}
int main() {
getBaseHashCode<B>();
getBaseHashCode<C>();
}
This will solve also the problem due to multiple inheritance. The designer of base_of specializations will be in charge to promote one of the base classes to the role of preferred one.
If my base class has a function func(int) and my derived class has a function func(double), the derived func(double) hides base::func(int). I can use using to bring the base version into the derive's list of overloads:
struct base
{
void func(int);
};
struct derived : base
{
using base::func;
void func(double);
}
OK, great. But what if I'm not sure whether base has a func() or not? ie because I am doing template metaprogramming, I'm not actually sure what base is, but I want to bring its functions up to the same level - if they exist. ie change the above example to:
struct base_with
{
void func(int);
};
struct base_without
{
};
template <typename Base>
struct derived : Base
{
using Base::func; // if Base has a func(), I want to bring it in
void func(double);
}
derived<base_with> testwith; // compiles
derived<base_without> testwithout; // fails :-(
I need using_if like boost::enable_if. Doesn't seem possible...
Thanks in advance.
Since you're willing to put using statements into your derived class, I assume you know beforehands which members you may be interested to bring in. You can do this using boost::enable_if:
struct base_with
{
void func(int) { cout << "func(int)" << endl; }
};
struct base_without { };
// Custom traits, by default assume func() isn't present
template <class T> struct has_func : public boost::false_type { };
template<> struct has_func<base_with> : public boost::true_type { };
// Again, if nothing else is known, assume absence of func(int)
template <typename Base, class UseFunc = void> struct derived : Base
{
derived() { cout << "ctor: derived without" << endl; }
void func(double) { cout << "func(double)" << endl; }
};
// Derived with func(int)
template <typename Base> struct derived<Base, typename boost::enable_if< has_func<Base> >::type> : Base
{
using Base::func;
derived() { cout << "ctor: derived with" << endl; }
void func(double) { cout << "func(double)" << endl; }
};
Sorry for all the printing statements. Now if you try
derived<base_with> testwith;
derived<base_without> testwithout;
testwith.func(10);
testwith.func(10.5);
testwithout.func(10);
testwithout.func(10.5);
you should see
ctor: derived with
ctor: derived without
func(int)
func(double)
func(double)
func(double)
Obviously, this is going to get monstrous if you try to test for several features. If I was doing such mixin-style programming, I'd probably rather use functions with different names for different features so they wouldn't hide each other - then public inheritance would be all that is needed. Interesting question in any case.
I guess I need to do something like
struct dummy_func
{
private:
struct dumb_type {};
// interesting: does this need to be public?
public:
// use a type that no one can see, so func is never chosen by ADT
// and vararg just for paranoia
void func(dumb_type, dumb_type, dumb_type,...) { };
};
...
template <typename T>
struct has_func
{
enum { value = /* insert metaprogramming magic that checks for T::func */ }
};
template <typename Base>
struct derived : Base
{
using enable_if<has_func<Base>, Base, dummy_func>::type::func;
...
};
grrr. Of course this doesn't work because dummy_func is not a base of derived. In my case I could maybe make it derive from it when necessary. But still barely satisfactory.