Given the following:
class Observer
{
public:
virtual void Observe(Parameter p) = 0;
};
template<size_t Tag>
class TaggedObserver : public Observer { };
class Thing : public TaggedObserver<0>, TaggedObserver<1>
{
public:
virtual void Observe(Parameter p) override;
};
Thing::Observe overrides both TaggedObserver<0>::Observe and TaggedObserver<1>::Observe.
Is there a way to provide a different override for each base class?
Rationale: I want the class to be able to observe two notification sources of the same type with different actions for each source without having to resort to pass the source in the parameter and then checking it in an if/switch.
In order to provide different overrides, you need to define different derived classes, eg:
class Observer
{
public:
virtual void Observe(Parameter p) = 0;
};
template<size_t Tag>
class TaggedObserver : public Observer
{
};
class TaggedObserverZero : public TaggedObserver<0>
{
public:
virtual void Observe(Parameter p)
{
// do something ...
}
};
class TaggedObserverOne : public TaggedObserver<1>
{
public:
virtual void Observe(Parameter p)
{
// do something else ...
}
};
However, if you want Thing::Observe() to receive the Parameter first and dispatch it to the appropriate base class, you can't avoid using an if statement (or equivalent) in Thing, since it inherits multiple copies of TaggedObserver::Observe() and needs to decide which one to call:
class Thing : public Observer, TaggedObserverZero, TaggedObserverOne
{
public:
virtual void Observe(Parameter p)
{
if (some condition)
TaggedObserverZero::Observe(p);
else if (some other condition)
TaggedObserverOne::Observe(p);
}
};
Or, you call just them both unconditionally and let them figure out what to do:
class TaggedObserverZero : public TaggedObserver<0>
{
public:
virtual void Observe(Parameter p)
{
if (some condition)
// do something ...
}
};
class TaggedObserverOne : public TaggedObserver<1>
{
public:
virtual void Observe(Parameter p)
{
if (some other condition)
// do something else ...
}
};
class Thing : public Observer, TaggedObserverZero, TaggedObserverOne
{
public:
virtual void Observe(Parameter p)
{
TaggedObserverZero::Observe(p);
TaggedObserverOne::Observe(p);
}
};
Implement them in TaggedObserver (provide explicit specialization if needed), as an example:
class Observer {
public:
virtual void Observe(Parameter p) = 0;
};
template<size_t Tag>
class TaggedObserver : public Observer {
public:
void Observe(Parameter p) override { }
};
template<std::size_t... I>
class Thing : public TaggedObserver<I>... {
public:
Thing(): TaggedObserver<I>{}... {}
template<std::size_t N>
void Observe(Parameter p) {
TaggedObserver<N>::Observe(p);
}
};
Then, you can specialize Thing as Thing<0, 1> and invoke the right function using thing.Observe<1>(p).
EDIT
The purpose of this edit is to show a new example code, that is more or less the one above even if slightly modified.
I hope this can help the OP. The basic idea is to combine CRTP idiom, virtual methods and inheritance.
class Observer {
public:
virtual void Observe(Parameter p) = 0;
};
template<template T, size_t Tag>
class TaggedObserver : public Observer {
public:
void Observe(Parameter p) override {
T *t = static_cast<T*>(this);
// Now use whatever you want from T, that is Thing in this example
}
};
template<std::size_t... I>
class Thing : public TaggedObserver<Thing<I...>, I>... {
template<std::size_t J>
friend class TaggedObserver<Thing<I...>, J>;
public:
Thing(): TaggedObserver<Thing<I...>, I>{}... {}
template<std::size_t N>
void Observe(Parameter p) {
TaggedObserver<Thing<I...>, N>::Observe(p);
}
};
Note that the friend declaration allows TaggedObservers to access private members of Thing.
This way, implementations of Observe in TaggedObservers can access public, protected and private members from Thing, as requested in the comments.
Finally you can specialize TaggedObserver if needed, so as to provide different implementations for Observe.
As an example:
template<template T, size_t Tag>
class TaggedObserver;
template<template T>
class TaggedObserver<T, 0>: public Observer {
public:
void Observe(Parameter p) override {
T *t = static_cast<T*>(this);
// Now use whatever you want from T, that is Thing in this example
// Put here the code of the specialization for Tag 0
}
};
template<template T>
class TaggedObserver<T, 1>: public Observer {
public:
void Observe(Parameter p) override {
T *t = static_cast<T*>(this);
// Now use whatever you want from T, that is Thing in this example
// Put here the code of the specialization for Tag 1
}
};
Related
How to create many classes to act like implementer for an interface class, while avoid v-table cost as possible, and still enable static casting to the interface?
For a simple case, it can be achieved like in the below example.
Example
Library Code :-
class I{ //interface
public: virtual void i1()=0;
};
template<class Derived>class Router : public I{
public: virtual void i1()final{
//in real case it is very complex, but in the core is calling :-
static_cast<Derived*>(this)->u1();
}
};
User Code :-
class User : public Router<User>{
public: void u1(){ std::cout<<"hi"<<std::endl; }
};
int main() {
User u;
u.i1(); //<-- no v-table cost
I* i=&u;
i->i1(); //<-- has v-table cost (OK)
}
Full demo
Question
How to extend the above feature to support 2 routes or more?
The below code is uncompilable, but it depicts my dream. (full demo).
Library Code :-
class I{ //interface
public: virtual void i1()=0;
public: virtual void i2()=0;
};
template<class Derived>class RouterI1U1 : public I{
public: virtual void i1()final{ static_cast<Derived*>(this)->u1(); }
};
template<class Derived>class RouterI1U2 : public I{
public: virtual void i1()final{ static_cast<Derived*>(this)->u2(); }
};
template<class Derived>class RouterI2U1 : public I{
public: virtual void i2()final{ static_cast<Derived*>(this)->u1(); }
};
template<class Derived>class RouterI2U2 : public I{
public: virtual void i2()final{ static_cast<Derived*>(this)->u2(); }
};
User Code :-
The one who want to use the above library, can easily pick whatever "route" he want.
derived from RouterI1U2<User> and RouterI2U1<User> or
derived from RouterI1U1<User> and RouterI2U2<User> or
derived from {RouterI1U1<User> or RouterI1U2<User>} and implement i2() with final manually or
derived from {RouterI2U2<User> or RouterI2U1<User>} and implement i1() with final manually or
implement i1() and i2() with final manually
Here is an dreamed example of usage.
class User : public RouterI1U2<User>,public RouterI2U1<User>{
public: void u1(){ std::cout<<"hi1"<<std::endl; }
public: void u2(){ std::cout<<"hi2"<<std::endl; }
};
int main() {
User u;
u.i1(); //<-- no v-table cost
I* i=&u;
i->i1(); //<-- has v-table cost (OK)
}
My poor solution
class I{ //interface
public: virtual void i1()=0;
public: virtual void i2()=0;
};
template<class Derived> class RouterI1U2_I2U1 : public I{ //group it
public: virtual void i1()final{ static_cast<Derived*>(this)->u2(); }
public: virtual void i2()final{ static_cast<Derived*>(this)->u1(); }
};
class User : public RouterI1U2_I2U1<User>{
public: void u1(){ std::cout<<"hi1"<<std::endl; }
public: void u2(){ std::cout<<"hi2"<<std::endl; }
};
It works (demo), but offer less modularity. (low re-usability)
I have to pack RouterI1U2 and RouterI2U1 to RouterI1U2_I2U1 manually.
It may not apply in your case, but could be useful to other reading the question as well.
I suggest you to use the concept-model idiom for this particular case. The goal of this is to separate the polymorphism implementation and the implementation of those class themselves into different part. Here, I becomes a polymorphic wrapper around any class that has i1 and i2 member functions:
class I {
// The interface is internal, invisible to outside
// We use this as a type erasure technique and polymorphism
struct Concept {
virtual void i1() = 0;
virtual void i2() = 0;
};
// The single implementation that directly
// extend the interface is the model. T is the user class.
// T must have i1 and i2 function, because we call them.
template<typename T>
struct Model : Concept {
// The user class.
// If you want, you can use a reference there if you
// need references semantics with I
T user;
Model (T u) : user{std::move(u)} {}
// The only implementation of i1 is to call i1 from the user class
void i1() override {
user.i1();
}
void i2() override {
user.i2();
}
};
// Or use a shared, or use SBO
std::unique_ptr<Concept> concept;
public:
// When we make an I, we must provide a user class.
// If the user class had i1 and i2, it will compile.
// If Model takes a reference, use a reference there too.
template<typename T>
I(T model) : concept{std::make_unique<Model<T>>(std::move(model))} {}
void i1() {
concept->i1();
}
void i2() {
concept->i2();
}
};
Then, your classes that provide implementations becomes like this:
template<class Derived>
struct RouterI1U1 { // no Inheritance needed
void i1() { static_cast<Derived*>(this)->u1(); }
};
template<class Derived>
struct RouterI1U2 {
void i1() { static_cast<Derived*>(this)->u2(); }
};
template<class Derived>
struct RouterI2U1 {
void i2() { static_cast<Derived*>(this)->u1(); }
};
template<class Derived>
struct RouterI2U2 {
void i2() { static_cast<Derived*>(this)->u2(); }
};
Since these i1 and i2 only needs to be "there" in order to fit into the Model<T> class, no overriding is needed, so no virtual inheritance.
It would effectively look like this when used:
struct User : RouterI2U2<User> {
void i1() {}
void u2() {}
};
As you can see, we don't have any virtual method. The polymorphism is an implementation detail of I. Since this class have all required member functions, the I class will allow it.
And using the class I too is quite simple. Let User2 be another user class that fits I requirements:
User2 user2;
user2.i1(); // no vtable, so no vtable overhead possible
I myI{user2}; // works!
myI.i2(); // calls u2, with vtable
std::vector<I> v;
v.emplace_back(User2{});
v.emplace_back(User{}); // simple heh?
Here's how you can remove the router classes, and implement this thing with an "or" style interface. I mean an interface that allows you to implement something or something else.
In the Model<T> class, you can check if i1 and i2 exists. If there are not existing, you can provide an implementation that calls u1 and u2 instead.
We start that by making type traits that can tell us if a particular type T has the member function i1 or i2:
template<typename...>
using void_t = void;
template<typename, typename>
struct has_i1 : std::false_type {};
template<typename T>
struct has_i1<T, void_t<decltype(std::declval<T>().i1())>> : std::true_type {};
template<typename, typename>
struct has_i2 : std::false_type {};
template<typename T>
struct has_i2<T, void_t<decltype(std::declval<T>().i2())>> : std::true_type {};
Now, we can change our model implementation to call u1 or u2 if i1 and i2 are not there:
template<typename T>
struct Model : Concept {
T user;
Model(T u) : user{std::move(u)} {}
void i1() override {
i1_helper(user);
}
void i2() override {
i2_helper(user);
}
private:
template<typename U>
auto i1_helper(U& u) -> std::enable_if_t<has_i1<U>::value> {
// Call i1 if has i1
u.i1();
}
template<typename U>
auto i1_helper(U& u) -> std::enable_if_t<!has_i1<U>::value> {
// Call u1 if has not i1
u.u1();
}
template<typename U>
auto i2_helper(U& u) -> std::enable_if_t<has_i2<U>::value> {
// Call i2 if has i2
u.i2();
}
template<typename U>
auto i2_helper(U& u) -> std::enable_if_t<!has_i2<U>::value> {
// Call u2 if has not i2
u.u2();
}
};
Now, your user classes are the simplest possible.
struct User1 {
void i1() {}
void i2() {}
};
struct User2 {
void i1() {}
void u2() {}
};
struct User3 {
void u1() {}
void i2() {}
};
struct User4 {
void u1() {}
void u2() {}
};
Use virtual inheritance.
template<class Derived>class RouterI1U1 : public virtual I{
etc. makes the code compilable.
Say I've got the following (pseudo-)code:
class base{
public:
virtual void callMe() = 0;
virtual void doRender() = 0;
}
class a : public base{
public:
virtual void callMe(){/*doA*/} override;
}
class b : public base{
public:
virtual void callMe(){/*doB*/} override;
}
class myClass : public base, public a, public b{
public:
virtual void doRender(){
this->a::callMe();
this->b::callMe();
} override;
}
Would there be a way to write this differently? Something like:
class myClass : public base, public a, public b{
public:
virtual void doRender(){
this->allSupers::callMe();
} override;
}
My goal with this would be to have a base class that can be extended to have different "features", all of which have to be executed on doRender.
I know I could of course keep track of these functions by means of a function pointer list in base, in which the subclasses put their own functions when constructed, but I'd like to avoid that. Having to iterate over these functions still gives me at least three lines of code in my final doRender. (Or one long unreadable line.)
I'm open for suggestions using templates.
Depending on you actual problem at hand, you might be able to use the mixin-style. Essentially you can have each class call the next callMe at the end (or begining) of their own callMe. One benefit is that callMe does not need to be a virtual function. Here is a minimal example (online):
#include <iostream>
class base
{
public:
void callMe() {}; // Empty base case
virtual void doRender() = 0;
};
template <class super>
class a : public super
{
public:
void callMe()
{
std::cout << "doA" << '\n';
super::callMe(); // Call the next
};
};
template <class super>
class b : public super
{
public:
void callMe()
{
std::cout << "doB" << '\n';
super::callMe(); // Call the next
};
};
template <class super>
class myClass_t : public super
{
public:
void doRender()
{
super::callMe();
};
};
using myClass = myClass_t<a<b<base> > >; // Defining the order of evaluation;
int main()
{
myClass m;
m.doRender();
}
With variadic template, you may do:
template <typename ... Ts>
class myClassTs : public base, public Ts...
{
public:
virtual void doRender(){
int dummy[] = {0, (Ts::callMe(), void(), 0)...};
static_cast<void>(dummy); // Silent warning for unused variable
} override;
}
using myClass = myClassTs<a, b>;
And in C++17, it would be
template <typename ... Ts>
class myClassTs : public base, public Ts...
{
public:
virtual void doRender(){
(static_cast<void>(Ts::callMe()), ...);
} override;
}
I got strange code and have to extend it. But instead of copy paste many many times i decided to create a template. But get caught by a terrible rock.
Here is an example code:
template<typename T>
class anyClass {};
template<typename T>
class Outer : public anyClass<T>
{
public:
using value_t = T;
class Inner
{
virtual void foo(value_t);
};
};
class specializer : protected Outer::Inner
{
virtual void foo(int) override {}
}
I have to extend virtual void foo(value_t) in specializer.
Example:
class specializer : protected Outer::Inner
{
virtual void foo(int) override {}
virtual void foo(float) override {}
virtual void foo(string) override {}
virtual void foo(bar) override {}
// And so on...
}
Question 1: Why works the example, although class specializer : protected Outer::Inner miss a param?
All overloadings do nearly the same. I created already the function.
template<typename anyType>
void meow( anyType )
{
/***/
}
My problem is here:
virtual void foo(anytype value) //<< replace anytype with what?
{
meow<anytype>( value );
}
I need the type Outer::value_T but i don't know how to get it.
Question 2: How can i use meow by calling foo ?
Feel free to ask for more information.
UPDATE
I looked again in the origin code and realised, that i've overlooked an important using/typedef.
The working code looks like:
class specializer : protected Outer<int, float, string, bar>::Inner //Yes a variadic-template
{
virtual void foo(int) override {}
virtual void foo(float) override {}
virtual void foo(string) override {}
virtual void foo(bar) override {}
// And so on...
}
So Question 1 is solved.
Why works the example, although class specializer : protected Outer::Inner miss a param?
The example does not work. It does not work because Outer is not a type. Also, you override multiple overloads of foo even though inner has only one foo. There are several syntax errors too. If it appears to work, then the compiler is doing something non-standard.
About your second question:
virtual void foo(anytype value) //<< replace anytype with what?
You replace it with the type whose overload you intend to override. For example, if you intend to override foo(int), then replace anytype with int.
Question 2: How can i use meow by calling foo ?
Simply call meow in foo.
You would have to make specializer a template class.
#include <iostream>
template<typename T> void meow(T x)
{
std::cout << x << std::endl;
}
template<typename T>
class anyClass {};
template<typename T>
class Outer : public anyClass<T>
{
public:
using value_t = T;
class Inner
{
virtual void foo(Outer<T>::value_t);
};
};
template<typename T>
class specializer : protected Outer<T>::Inner
{
virtual void foo(T x) override
{
meow(x);
}
};
I wonder how this would help you to change the behavior in Outer or anyClass because you have not shown code which shows where and how Inner is actually used. Without that, it's just guessing.
I have the feeling that what you are actually trying to achieve is to pass a function (or Strategy?) to you Outer class, represented by Inner in your code. That would be better done by passing it as a template argument.
template<typename T>
class anyClass {};
template<typename T, typename Inner = meow<T>>
class Outer : public anyClass<T>
{
public:
using value_t = T;
// somewhere in your code
Inner i;
i.meow( any_value );
};
You can also pass a std::function to the constructor.
template
class anyClass {};
template<typename T>
class Outer : public anyClass<T>
{
public:
using value_t = T;
Outer( std::function<void (value_t)> inner);
// somewhere in your code
i.meow( any_value );
std::function<void (value_t)> i;
};
Originally I simplyfied a little bit to much.
Here is the compileable example of my problem: http://ideone.com/9U7J1a
I removed all unconducive code. I know the design is horrible but i have no influence on it.
class bar {};
class string {};
template<typename _T>
class ModelContainer
{
public:
using value_type = _T;
class Delegate {
public:
virtual void foo( value_type value);
};
};
template< typename... _Ts >
class ModelManager__AbstractBase : protected ModelContainer< _Ts >...
{
public:
class Delegate : public ModelContainer< _Ts >::Delegate... {
public:
virtual ~Delegate( ) = default;
};
};
using ModelManager__Base = ModelManager__AbstractBase<
int,
float,
string,
bar
>;
class ModelManager : public ModelManager__Base {
/* Some functions */
};
class spezializer : ModelManager::Delegate
{
public:
virtual ~spezializer() = default;
//Uncommend to see my error
// virtual void foo( value_type value) override // << value_type unknown
// {/* Calling everytime the same method, no matter which value_type*/}
};
template <typename T>
class BaseQueue
{
public :
virtual void push_back(T value) = 0;
//other virtual methods
};
template <typename T>
class BaseDeque: public virtual BaseQueue<T>
{
public:
virtual void push_front(T value) = 0;
//other virtual methods
};
//Realisation
template <typename T>
class VectorQueue: public BaseQueue<T>
{
typedef typename std::vector<T> array;
private: array adata;
public:
VectorQueue()
{
adata = array();
}
void push_back(T value)
{
adata.push_back(value);
}
};
template <typename T>
class VectorDeque: virtual public VectorQueue<T>, virtual protected BaseDeque<T>//,
{
void push_front(T value)
{
VectorQueue::adata.push_front(value);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
VectorDeque<int> vd = VectorDeque<int>();//here is a error
int i;
std::cin >> i;
return 0;
}
I have such error: "C2259: 'VectorDeque' : cannot instantiate abstract class ...". How can I fix it? Class VectorQueue has realize every virtual method of BaseQueue class already. But the compiler doesn't know it. The only way I see is to write something like this:
template <typename T>
class VectorDeque: virtual public VectorQueue<T>, virtual protected BaseDeque<T>//,
{
void push_front(T value)
{
VectorQueue::adata.push_front(value);
}
void push_back(T value)
{
VectorQueue::push_back(value);
}
//repeat it fo every virtual method of BaseQueue class (interface)
};
But it's awful.
push_back from BaseQueue isn't implemented on the BaseDeque side of the inheritance chain, and thus the childmost class is still abstract.
I think you're trying to force a class relationship here that shouldn't exist. Note how in the standard library deque and vector are distinct container types and things like queue adapt those containers to very precise interfaces rather than trying to inherit.
Even if you solve your diamond issue (or follow #Mark B's advice and keep them separate), you have a few other issues in there:
template <typename T>
class VectorQueue: public BaseQueue<T>
{
typedef typename std::vector<T> array;
private: array adata; // if this is private, VectorDeque can't reach it
public:
// constructors have an initializer section
// member variables should be initialized there, not in the body
VectorQueue()
// : adata() // however, no need to explicitly call default constructor
{
// adata = array();
}
};
template <typename T>
class VectorDeque: virtual public VectorQueue<T>, virtual protected BaseDeque<T>
{
void push_front(T value)
{
// if adata is protected, you can just access it. No need for scoping
/*VectorQueue::*/ adata.push_front(value);
// Error: std::vector doesn't have a method push_front.
// Perhaps you meant to use std::list?
}
};
Multiple inheritance and static polymorphism are of help, for instance:
// Abstract bases
template <typename T, typename Val>
class BaseQueue
{
public :
void push_back(Val val)
{
static_cast<T*>(this)->push_back(val);
}
// ...
};
template <typename T, typename Val>
class BaseDeque
{
public:
void push_front(Val val)
{
static_cast<T*>(this)->push_front(val);
}
// ...
};
// Concrete class
#include <deque>
template <typename Val>
class QueueDeque:
public BaseQueue<QueueDeque<Val>, Val>,
public BaseDeque<QueueDeque<Val>, Val>
{
std::deque<Val> vals;
public:
void push_front(Val val)
{
vals.push_front(val);
}
void push_back(Val val)
{
vals.push_back(val);
}
// etc..
};
int main()
{
QueueDeque<int> vd;// no more error
vd.push_front(5);
vd.push_back(0);
return 0;
}
Is there any way to do this automatically for all derived classes, that i don't have to create function applyPack for all nested classes.
This is piece of my code:
/** every class has registered id with this function */
template<typename T>
uint getID() {
static uint id = registerClass<T>();
return id;
}
class TemplatesPack {
public:
template<typename T>
typename T::Template get();
};
class Object {
public:
virtual void applyPack(TemplatesPack *p) { this->setTemplate(p->get<Object>()); };
};
class Object2: public Object {
public:
void applyPack(TemplatesPack *p) { this->setTemplate(p->get<Object2>()); };
};
class Object3: public Object {
public:
void applyPack(TemplatesPack *p) { this->setTemplate(p->get<Object3>()); };
};
class Object4: public Object2 {
public:
void applyPack(TemplatesPack *p) { this->setTemplate(p->get<Object4>()); };
};
I've read something about type traits but i don't want to have class Object templated. Can be this done with c++ and templating some functions in class TemplatesPack or with c++0x? s
Edit:
changed the answer to make the Object untouched.
template<class T>
class Base<T> : public Object
{
public:
virtual void applyPack(TemplatePack *p) { this->setTemplate(p->get<T>()); };
};
class Object2 : public Base<Object2>
{
// ...
};
Edit: for the case of Object4, maybe the following will help:
template<class S, class D>
class Base<S, D> : public S
{
public:
virtual void applyPack(TemplatePack *p) { this->setTemplate(p->get<D>()); };
};
class Object2 : public Base<Object, Object2> { /* ... */ };
class Object3 : public Base<Object, Object3> { /* ... */ };
class Object4 : public Base<Object2, Object4> { /* ... */ };
You could use virtual inheritance and the dominance rule, if you don't want to templatize Base
template<typename Derived, typename Base = void>
struct applyer : virtual applyer<Base, typename Base::base_type> {
virtual void applyPack(TemplatesPack *p) {
dynamic_cast<Derived*>(this)->setTemplate(p->get<Derived>());
};
typedef Base base_type;
};
template<typename Derived>
struct applyer<Derived, void> {
virtual void applyPack(TemplatesPack *p) {
dynamic_cast<Derived*>(this)->setTemplate(p->get<Derived>());
};
};
Now you can do it as follows
class Object : virtual public applyer<Object> {
};
class Object2: public Object, virtual public applyer<Object2, Object> {
};
class Object3: public Object, virtual public applyer<Object3, Object> {
};
The second argument respectively is the direct base class, which can be omitted if there is none. For instance if you derive from Object3, you need to do that as follows
class Object3_1: public Object3, virtual public applyer<Object3_1, Object3> {
};