I am trying to create something similar to a type-safe multiqueue. The idea is that when I push an item, it will be added to a queue consisting of objects of the same type.
All the queues will have a common interface(the queue_intf in this case) that will do some processing.
The code I came up is the following:
#include <queue>
#include <vector>
#include <memory>
#include <stdlib.h>
class queue_intf {
public:
virtual void process(void) = 0;
};
template <typename T>
class queue : public queue_intf {
public:
std::queue<T> q_;
static const char* name()
{
return typeid(T).name();
}
virtual void process(void) override {
printf("process: %s\n", this->name());
}
void push(T &a) {
printf("push: %s\n", this->name());
}
};
template <typename...>
class queues {
public:
std::vector<queue_intf *> qs_;
void process(void) {
for (auto q: this->qs_) {
q->process();
}
}
};
template <typename T, typename... Ts>
class queues<T, Ts...> : public queues<Ts...> {
public:
queue<T> q_;
queues() {
this->qs_.push_back(&this->q_);
}
void push(T &v) {
q_.push(v);
}
};
class a {
};
class b {
};
int
main (int argc, char *argv[])
{
queues<a, b> qs;
a ai;
b bi;
qs.push(ai);
qs.process();
qs.push(bi);
}
However when I compile it I get the following error:
main.cc: In function ‘int main(int, char**)’:
main.cc:65:15: error: no matching function for call to ‘queues<a, b>::push(b&)’
qs.push(bi);
^
main.cc:45:10: note: candidate: void queues<T, Ts ...>::push(T&) [with T = a; Ts = {b}]
void push(T &v) {
^~~~
main.cc:45:10: note: no known conversion for argument 1 from ‘b’ to ‘a&’
I was expecting the queue class to have void push(b &v) method, but it seems it doesn't.
Any idea why?
Edit:
Here is a smaller example (no std:vector or anything):
template <typename...>
class queues {
};
template <typename T, typename... Ts>
class queues<T, Ts...> : public queues<Ts...> {
public:
void push(T &v) {
}
};
class a {
};
class b {
};
int
main (int argc, char *argv[])
{
queues<a, b> qs;
a ai;
b bi;
qs.push(ai);
qs.push(bi);
}
To explain this, let's use a simplified example, you have just two classes:
class base {
public:
void method(int *);
};
class derived : public base {
public:
void method(char *);
};
And you attempt to call it:
derived d;
int i;
d.method(&i);
This fails. Name lookup starts at the given derived class, and finds a matching class method with the specified name: method. However its parameter doesn't match, so this is ill-formed. If the derived class had both methods, overload resolution will pick the matching one. But once a class method with the specified name is found any parent class will not be searched for any other methods with the same name. Only if the derived class does not have any methods with the specified name does name lookup continue with the parent class(es).
Putting
using base::method;
In the derived class imports base's method into the derived's namespace, at which point everything works just like with regular overload resolution.
This is why you need a using declaration with your recursive templates. The second derived template imports it from the first one, the next one imports everything from the second derived template, and so on.
Related
I'm modifying a class by adding a data-member that is templated. The code will invariably be using a default template type for the template parameter in all invocations, except for one place. Partially motivated by this, and partially due to a a desire/whim, I do not want to add a template parameter to the class as shown below:
#include <iostream>
template <typename Der>
class A : private Der {
public:
int get() { return Der::get_(); }
};
class B {
protected:
int get_() { return 20; }
};
class C {
protected:
int get_() { return 30; }
};
using Default = B;
template <class T = Default>
class User {
public:
User() {}
A<T>& getMember() { return m_; }
private:
A<T> m_; // This is what I am adding, and exposing param T.
};
int main(int argc, char* argv[]) {
User h;
std::cout<<h.getMember().get()<<std::endl;
}
One solution that I could think of is the use of a sum-type, but this introduces some exception handling code:
class User {
public:
User() : m_(A<Default>()) {}
template <typename T>
User(const T& in) : m_(in) {}
template <typename T>
A<T>& getMember() { return std::get<A<T>>(m_); }
private:
std::variant<A<B>, A<C>> m_;
};
I'm looking for:
A name for what I am trying to do, if it exists.
Ways in which I can accomplish what I desire.
This is not an answer, as I don't find the virtual function call completely satisfactory, but, as progress, another option I can share is type-erasure using an inner base class.
Something like:
#include <iostream>
#include <memory>
class User {
public:
template <class T>
User(T&&) : m_(new Internal<T>()) {}
int doOnMember() { return m_->doOnMember(); }
private:
class InternalBase {
public:
virtual int doOnMember() = 0;
};
template <typename T>
class Internal : public InternalBase {
public:
Internal() {}
int doOnMember() { return m_.get(); }
private:
A<T> m_;
};
private:
std::shared_ptr<InternalBase> m_;
};
int main(int argc, char* argv[]) {
User h(B{});
std::cout<<h.doOnMember()<<std::endl;
User h1(C{});
std::cout<<h1.doOnMember()<<std::endl;
}
I'm having trouble using template member functions and template variables. The goal is to create an template for an interface which can be inherited and linked to one or more services initialized at runtime. This interface would also pass data to these specialized services (e.g. MyService). For a simpler example, with this code:
#include <string>
class Interface
{
public:
template <class T> bool init(T *_Service) {AttachService(*_Service);} //This function does other stuff too.
template <typename T> void AttachService(T _Service) { m_AttachedService<T> = *_Service; }
template <typename T> T AttachedService() { return m_AttachedService; }
protected:
template<typename T> static T m_AttachedService;
class InterfaceListener
{
void Received()
{
int a = 1;
std::string b = "hello";
AttachedService().setA(a);
m_AttachedService.setB(b);
};
};
};
class Service
{
Service();
~Service();
virtual void init() = 0;
};
class MyService : public Service, public Interface
{
MyService();
~MyService();
private:
int A;
std::string B;
protected:
Interface x;
public:
void init() { x.init(this);}
void setA(int a) { A = a; }
void setB(std::string b) { B = b; }
};
int main();
{
MyService myserv;
myserv.init();
}
I get the following errors:
C2672: 'Interface::AttachedService': no matching overloaded function found
C2783: 'T Interface::AttachedService(void)': could not deduce template argument for 'T'
C2228: left of '.setA' must have class/struct/union
C3245: 'Interface::m_AttachedService': use of a variable template requires template argument list
Any help understanding proper usage of templates would be appreciated!
Let's start with a minimal program that builds and runs without doing anything useful.
#include <string>
class Interface
{
};
class Service
{
protected:
Service() {}
~Service() {}
virtual void init() = 0;
};
class MyService : public Service, public Interface
{
private:
int A;
std::string B;
protected:
Interface x;
public:
MyService() {}
~MyService() {}
void init() {}
void setA(int a) { A = a; }
void setB(std::string b) { B = b; }
};
int main()
{
MyService myserv;
myserv.init();
}
You'll notice that there are few changes from your posted code to get to that baseline.
Interface is empty.
The member functions of Service are in public section. The default constructor and the destructor of Service have an empty implementation.
The default constructor and the destructor of MyService are in the public section of the class and they have empty implementations.
MyService::init() has an empty implementation.
Now we can start adding more code.
I changed MyService::init() to:
void init() { x.init(this); }
With no other changes, I got the following compiler error.
socc.cc: In member function ‘virtual void MyService::init()’:
socc.cc:25:23: error: ‘class Interface’ has no member named ‘init’
void init() { x.init(this);}
Now, Interface needs to be updated with an init function.
I added a dummy implementation to move the process forward.
class Interface
{
public:
template <class T> bool init(T *_Service) { return true; }
};
Time to add something useful to Interface::init(). Changing it to
template <class T> bool init(T *_Service)
{
AttachService(*_Service);
return true;
}
produces the following compiler error, which is not surprising.
socc.cc: In instantiation of ‘bool Interface::init(T*) [with T = MyService]’:
socc.cc:31:32: required from here
socc.cc:8:23: error: ‘AttachService’ was not declared in this scope
AttachService(*_Service);
~~~~~~~~~~~~~^~~~~~~~~~~
Time to add AttachService. Changing Interface to (closing matching what you have)
class Interface
{
public:
template <class T> bool init(T *_Service)
{
AttachService(*_Service);
return true;
}
template <typename T> void AttachService(T _Service)
{
m_AttachedService<T> = *_Service;
}
protected:
template<typename T> static T m_AttachedService;
};
produces the following compiler error.
socc.cc: In instantiation of ‘void Interface::AttachService(T) [with T = MyService]’:
socc.cc:8:10: required from ‘bool Interface::init(T*) [with T = MyService]’
socc.cc:39:32: required from here
socc.cc:14:33: error: no match for ‘operator*’ (operand type is ‘MyService’)
m_AttachedService<T> = *_Service;
^~~~~~~~~
That makes sense. In AttachServie, _Service is not a pointer.
Changing Inteface::AttachService to:
template <typename T> void AttachService(T _Service)
{
m_AttachedService<T> = _Service;
}
makes the compiler error go away but there is a linker error.
:socc.cc:(.rdata$.refptr._ZN9Interface17m_AttachedServiceI9MyServiceEE[.refptr._ZN9Interface17m_AttachedServiceI9MyServiceEE]+0x0): undefined reference to `Interface::m_AttachedService<MyService>'
collect2: error: ld returned 1 exit status
That makes sense since we have not defined the static member variable.
Adding the following line
template<typename T> T Interface::m_AttachedService;
right after definition of Interface takes care of the linker error.
The following is the next version of the complete program that builds successfully and runs even though it still doesn't do anything useful.
#include <string>
class Interface
{
public:
template <class T> bool init(T *_Service)
{
AttachService(*_Service);
return true;
}
template <typename T> void AttachService(T _Service)
{
m_AttachedService<T> = _Service;
}
protected:
template<typename T> static T m_AttachedService;
};
template<typename T> T Interface::m_AttachedService;
class Service
{
protected:
Service() {}
~Service() {}
virtual void init() = 0;
};
class MyService : public Service, public Interface
{
private:
int A;
std::string B;
protected:
Interface x;
public:
MyService() {}
~MyService() {}
void init() { x.init(this); }
void setA(int a) { A = a; }
void setB(std::string b) { B = b; }
};
int main()
{
MyService myserv;
myserv.init();
}
Time to add your version of the AttachedService to Interface
template <typename T> T AttachedService() { return m_AttachedService; }
That produces the following compiler error.
socc.cc: In member function ‘T Interface::AttachedService()’:
socc.cc:17:73: error: missing template arguments before ‘;’ token
template <typename T> T AttachedService() { return m_AttachedService; }
That makes sense since m_AttachedService is not a member variable but a member variable template.
Changing that to
template <typename T> T AttachedService() { return m_AttachedService<T>; }
removes that error.
Now the final piece in Interface. The nested class InterfaceListener that you have posted does sound right. You have
class InterfaceListener
{
void Received()
{
int a = 1;
std::string b = "hello";
AttachedService().setA(a);
m_AttachedService.setB(b);
};
};
Problems in that class:
AttachedService() is not right since it a member function template. You have to provide a template parameter to use it.
Also, AttachedService() is not a static member function. You need an instance of Interface to make that call.
m_AttachedService is not a member variable. It is a member variable template. You have to provide a template parameter to use it.
The functions setA() and setB() are valid only if the template parameter is MyService. It does not make sense to have code in that function that is specific to a type.
I'll leave it for you to ponder over how you intend to use InterfaceListener and define its functions appropriately. Until then the following program builds and runs for me.
#include <string>
class Interface
{
public:
template <class T> bool init(T *_Service)
{
AttachService(*_Service);
return true;
}
template <typename T> void AttachService(T _Service)
{
m_AttachedService<T> = _Service;
}
template <typename T> T AttachedService() { return m_AttachedService<T>; }
protected:
template<typename T> static T m_AttachedService;
};
template<typename T> T Interface::m_AttachedService;
class Service
{
protected:
Service() {}
~Service() {}
virtual void init() = 0;
};
class MyService : public Service, public Interface
{
private:
int A;
std::string B;
protected:
Interface x;
public:
MyService() {}
~MyService() {}
void init() { x.init(this); }
void setA(int a) { A = a; }
void setB(std::string b) { B = b; }
};
int main()
{
MyService myserv;
myserv.init();
}
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've two classes:
struct A {
template <typename T>
void print(T& t){
// do sth specific for A
}
};
struct B : A {
template <typename T>
void print(T& t){
// do sth specific for B
}
};
In such case, the more general Base class with virtual functions (which A and B both inherit from) cannot be compiled, since there is no virtual for template. As I try to delegate generally all A or B objects under same "interface", does anyone has the idea to resolve such problem? Thank you in advance.
Sincerely,
Jun
You can think about using using CRTP.
template<typename Derived>
struct Base {
template <typename T>
void print(T& t){
static_cast<Derived*>(this)->print(t);
}
};
struct A : Base<A> {
// template print
};
struct B : Base<B> {
// template print
};
Example Usage:
template<typename T, typename ARG>
void foo (Base<T>* p, ARG &a)
{
p->print(a);
}
This method will be called as,
foo(pA, i); // pA is A*, i is int
foo(pB, d); // pB is B*, d is double
Here is another demo code.
Using a proxy class to get B's method
class A {
public:
friend class CProxyB;
virtual CProxyB* GetCProxyB() = 0;
};
class B;
class CProxyB
{
public:
CProxyB(B* b){mb = b;}
template <typename T>
void printB(T& t)
{
mb->print(t);
}
B* mb;
};
class B:public A {
public:
virtual CProxyB* GetCProxyB(){return new CProxyB(this);};
template <typename T>
void print(T& t){
printf("OK!!!!!\n");
}
};
int _tmain(int argc, _TCHAR* argv[])
{
A* a = new B;
CProxyB* pb = a->GetCProxyB();
int t = 0;
pb->printB(t);
return 0;
}
Two options:
Option one: Virtualize the method where if the user does not provide an implementation, the Base class' is used.
template <typename T>
struct A {
virtual void print(T& t);
};
template <typename T>
void A::print(T& t) {
// do sth specific for A
}
template <typename T>
struct B : A {
virtual void print(T& t);
};
void B::print(T& t) {
// do sth specific for B
}
Option two: Abstract the method where if the user does not provide an implementation, the code will not compile.
template <typename T>
struct A {
virtual void print(T& t)=0;
};
template <typename T>
struct B : A {
virtual void print(T& t){
// do sth specific for B
}
};
template <typename T>
void B::print(T& t){
// do sth specific for B
}
Other than the above mentioned, if you do not make them virtual, the Derived class will Shadow the Base class method and that is most certainly not what you intended. Hence, impossible.
my question is how to use single pointer to different A or B objects.
You can do this without virtual functions per-se. But all you will really be doing is writing an implementation of a V-table and virtual functions.
If I were going to manually implement virtual functions, I would base it all on a Boost.Variant object. The variant would effectively hold the member data for each class. To call a function, you use a variant visitor functor. Each "virtual function" would have its own visitor functor, which would have different overloads of operator() for each of the possible types within the variant.
So you might have this:
typedef boost::variant<StructA, StructB, StructC> VirtualClass;
You could store any one of those objects in the variant. You would call a "virtual function" on the object like this:
VirtualClass someObject(StructA());
boost::apply_visitor(FunctorA(), someObject);
The class FunctorA is your virtual function implementation. It is a visitor, defined like this:
class FunctorA : public boost::static_visitor<>
{
void operator()(StructA &arg){
//Do something for StructA
}
void operator()(StructB &arg){
//Do something for StructB
}
void operator()(StructC &arg){
//Do something for StructC
}
}
Visitors can have return values, which are returned by apply_visitor. They can take arguments, by storing the arguments as members of the visitor class. And so forth.
Best of all, if you ever change your variant type, to add new "derived classes", you will get compiler errors for any functors that don't have overloads for the new types.
But to be honest, you should just be using virtual functions.
By using CRTP(Curiously recurring template pattern), you can achieve static polymorphsim without virtual.
#include <iostream>
using namespace std;
#define MSG(msg) cout << msg << endl;
template<class Derived>
class Base{
public:
void print()
{
static_cast<Derived*>(this)->print();
}
};
class Derived1 : public Base<Derived1>
{
public:
void print()
{
MSG("Derived 1::print");
}
};
class Derived2 : public Base<Derived2>
{
public:
void print()
{
MSG("Derived 2::print");
}
};
template<class T>
void callme(Base<T>& p)
{
p.print();
}
int main()
{
Base<Derived1> p1;
Base<Derived2> p2;
callme(p1);
callme(p2);
system("pause");
return 0;
}
//Result :
//Derived 1::print
//Derived 2::print
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;
}