How to make a variadic function of smart pointers? - c++

I'm trying to make an interface an abstract class which would be implemented by derivated childs. One of methods in that class has to be variadic (children get one ore more QSharedPointer<QObject> depending on implementation)
The problem is that:
templated methods cannot be virtual
I cannot make a variadic method taking QSharedPointer<QObject>... args arguments because of error: expansion pattern ‘QSharedPointer<QObject>’ contains no argument packs.
Less words, more code:
class BaseClass {
public:
virtual void foo(QSharedPointer<QObject>... args) = 0;
}
class ChildClassA : public BaseClass {
public:
void foo(QSharedPointer<QObject> arg1);
}
class ChildClassB : public BaseClass {
public:
void foo(QSharedPointer<QObject> arg1, QSharedPointer<QObject> arg2);
}
I would like to use above classes to things like that:
template <class T = BaseClass>
class Controller<T>{
void callFoo(QSharedPointer<QObject>... args){
T* = new T();
T->foo(args);
}
}
As you can see the BaseClass is only to say: use one of my children as generic type.
How do I make such things work? Is it even possible in C++?

Since (per the comments) you already have separated the children by arity, and they're managed by separate instantiations of a Controller class template, there is no point in trying to force them all into the same hierarchy -- that only means workarounds and runtime overhead.
Instead, let's make BaseClass a template, and use its parmeter to generate foo's signature.
namespace detail {
template <std::size_t, class T>
using expandHook = T;
}
template <std::size_t N, class = std::make_index_sequence<N>>
struct BaseClass;
template <std::size_t N, std::size_t... Idx>
struct BaseClass<N, std::index_sequence<Idx...>> {
virtual void foo(detail::expandHook<Idx, QSharedPointer<QObject>>... args) = 0;
};
detail::expandHook is kind of a syntactic trick to repeat the QSharedPointer<QObject> type as many times as there are Idxes, which are 0 to N - 1 thanks to the work of std::index_sequence.
Then, children inherit from the corresponding BaseClass:
struct Child : BaseClass<2> {
void foo(QSharedPointer<QObject>, QSharedPointer<QObject>) override;
};
Bonus: a child can inherit from several BaseClass specializations if you want it to support several arities!
Finally, a controller will be parameterized by the adequate BaseClass type, and everything clicks in.
See it live on Coliru (with stubbed types, and main's content would be what's inside a Controller).

If you follow the guideline that public functions should be non-virtual and virtual functions should be private, then you can solve this problem by turning the base function into a variadic template function which delegates to a virtual private function taking a std::vector.
This also has the advantage that all the unpacking happens in one place and derived classes are easier to implement.
Here is an example (I've replaced QSharedPtr with std::shared_ptr and added dummy implementations for QObject so that the example can be compiled without 3rd-party stuff):
#include <memory>
#include <vector>
#include <iostream>
#include <cassert>
struct QObject { virtual void sayHi() const = 0; };
struct DerivedQObject1 : public QObject { void sayHi() const override { std::cout << "1\n"; } };
struct DerivedQObject2 : public QObject { void sayHi() const override { std::cout << "2\n"; } };
class BaseClass {
public:
template <class... Types>
void foo(std::shared_ptr<Types>... args)
{
std::vector<std::shared_ptr<QObject>> vector;
pushBack(vector, args...);
assert(!empty(vector));
doFoo(vector);
}
private:
virtual void doFoo(std::vector<std::shared_ptr<QObject>> const& args) = 0;
template<typename LastType>
static void pushBack(std::vector<std::shared_ptr<QObject>>& vector, LastType arg)
{
vector.push_back(arg);
};
template<typename FirstType, typename ...OtherTypes>
static void pushBack(std::vector<std::shared_ptr<QObject>>& vector, FirstType const& firstArg, OtherTypes... otherArgs)
{
vector.push_back(firstArg);
pushBack(vector, otherArgs...);
};
};
class ChildClassA : public BaseClass {
private:
void doFoo(std::vector<std::shared_ptr<QObject>> const& args) override;
};
void ChildClassA::doFoo(std::vector<std::shared_ptr<QObject>> const& args) {
for (auto const& arg : args) {
arg->sayHi();
}
}
int main() {
ChildClassA child;
auto obj1 = std::make_shared<DerivedQObject1>();
auto obj2 = std::make_shared<DerivedQObject2>();
child.foo(obj1, obj2);
}

Related

How to casting class template based on template argument type

Currently, I store pointers of different types in a vector. To archive this, I implemented a class template "Store" which derives from a non-class template "IStore". My vector finally stores pointers to "IStore".
In code:
class IStore
{
public:
IStore() = default;
virtual ~IStore() = default;
virtual void call() = 0;
// ... other virtual methods
};
template<typename T>
class Store : public IStore
{
public:
Store() = default;
virtual ~Store() = default;
virtual void call() override;
// ... other virtual methods
private:
T* m_object = nullptr;
}
And in my main class which holds the vector:
class Main
{
public:
template<typename T>
void registerObject(T* ptr);
template<typename T>
void callObjects();
// ... other methods
private:
std::vector<IStore*> m_storedObjects;
};
So far the current class structure. To describe the problem I need to introduce the following three example structs:
struct A {}
struct B : public A {}
struct C : {}
Other classes should call the Main::registerObject method with pointers to objects of A, B or C types. This method will then create a new Store<A>, Store<B> resp. Store<C> template class object and inserts this objects pointer to m_storedObjects.
Now the tricky part starts: The method Main::callObjects should be called by other classes with a template argument, such as Main::callObjects<B>(). This should iterate though m_storedObjects and call the IStore::call method for each object, which is of type B or which type B is derived from.
For example:
Main::registerObject<A>(obj1);
Main::registerObject<B>(obj2);
Main::registerObject<C>(obj3);
Main::callObjects<B>();
Should call obj1 and obj2 but not obj3, because C isn't B and B isn't derived from C.
My approaches in Main::callObjects were:
1. Perform dynamic_cast and check against nullptr like:
for(auto store : m_storedObjects)
{
Store<T>* base = dynamic_cast<Store<T>*>(store);
if(base)
{
// ...
}
}
which will only work for the same classes, not derived classes, because Store<B> isn't derived from Store<A>.
2. To overwrite the cast operator in IStore and Store, such that I can specify Store should be castable when the template argument is castable. For example in Store:
template<typename C>
operator Store<C>*()
{
if(std::is_convertible<T, C>::value)
{
return this;
}
else
{
return nullptr;
}
}
But this method is never called.
Does anyone have a solution to this problem?
Sorry for the long post, but I thought more code would be better to understand the problem.
Thanks for your help anyway :)
After some thought, I realized that your type erasure, from assigning Store<T> objects to IStore* pointers, makes it impossible to use any compile-time type checking like std::is_base_of and the like. The next best option you have is run-time type information (dynamic_cast<>(), typeid()). As you observed, dynamic_cast<>() can't determine if an object's type is an ancestor of another type, only if an object's type is a descendant of another type known at compile time.
EDIT: With C++17 support, I can think of another way to solve your problem, based on the std::visit example here. If you change your Main interface...
#include <iostream>
#include <vector>
#include <variant>
template <typename T>
class Store {
public:
using value_type = T;
Store(T* object): m_object(object) {}
void call() { std::cout << "Hello from " << typeid(T).name() << '\n'; }
// ... other methods
private:
T* m_object = nullptr;
};
template <typename... Ts>
class Main {
private:
std::vector<std::variant<Store<Ts>...>> m_storedObjects;
public:
// replacement for registerObjects, if you can take all objects in at once
Main(Ts*... args): m_storedObjects({std::variant<Store<Ts>...>(Store<Ts>{args})...}) {}
template <typename U>
void callObjects() {
for (auto& variant : m_storedObjects) {
std::visit([](auto&& arg) {
using T = typename std::decay_t<decltype(arg)>::value_type;
if constexpr (std::is_base_of<T, U>::value) {
arg.call();
}
}, variant);
}
}
};
struct A {};
struct B : public A {};
struct C {};
int main() {
A a;
B b;
C c;
auto m = Main{&a, &b, &c};
m.callObjects<B>();
// > Hello from 1A
// > Hello from 1B
return 0;
}

Design issues with a controller construct managing different component implementations

I am wrapping my head around on a relatively simple problem, but seemingly cannot find a way to resolve this issue - even a bit hackish ..., I just got stuck and could use some idea that seem not to pop up. The code sample shown below is NOT (fully) working and is rather there to show my problem.
I have a controller class with 3 methods init, process and dispose. The Controller basically is a wrapper for one or more so called components to be executed.
Furthermore there is a component_manager class to create component instances and manage their life cycle. The component manager is derived from an interface defining 4 virtual methods, such as init, prepare, recycle and dispose.
A component itself also has a well defined interface icomponent. All components derive from that interface and all components are default constructable (no arguments needed).
To show some code I've extracted the important parts from the code I am experimenting with, leaving out the `controller' wrapper class and all the noise around it.
namespace detail {
// Iterator for std::tuple
template<typename Tuple, typename F, std::size_t ...Indices>
constexpr void for_each_impl(Tuple&& tuple, F&& f, std::index_sequence<Indices...>)
{
using swallow = int[];
(void)swallow{1,
(f(std::get<Indices>(std::forward<Tuple>(tuple))), void(), int{})...
};
}
} // Namespace detail
template<typename Tuple, typename F>
constexpr void for_each(Tuple&& tuple, F&& f)
{
constexpr std::size_t N = std::tuple_size<std::remove_reference_t<Tuple>>::value;
detail::for_each_impl(std::forward<Tuple>(tuple), std::forward<F>(f),
std::make_index_sequence<N>{});
}
// A component
class icomponent {
public:
virtual ~icomponent() = default;
virtual std::string id() = 0;
};
// Sample components a, b and c
class component_a : public icomponent {
public:
virtual std::string id() override { return "component a"; }
};
class component_b : public icomponent {
public:
virtual std::string id() override { return "component b"; }
};
class component_c : public icomponent {
public:
virtual std::string id() override { return "component c"; }
};
// Interface defining a component manager
class iprocessing_component_manager
{
public:
virtual ~iprocessing_component_manager() = default;
virtual T* prepare() = 0;
// More members like init(), recycle() and dispose()
};
// An simple, possible implementation of component manager
class simple_processing_component_manager
: public iprocessing_component_manager
{
public:
virtual ~simple_processing_component_manager() = default;
// ... other implemented methods ...
virtual T* prepare()
{
// ... creation of component
}
};
// In the controller wrapper, the process method
template<typename ...T>
void process()
{
// This initialization is normally within the controller wrapper
std::unique_ptr<simple_processing_component_manager> component_mgr = std::make_unique<simple_processing_component_manager>();
// Convert to tuple
std::tuple<T...> components;
// Iterate over (component) types ...
for_each(components, [&](auto& comp) {
using component_t = typename std::remove_reference<decltype(comp)>::type;
// Steps would be ...
// Instantiate the component (doesn't work, just showing what I need to accomplish)
component_t* x = component_mgr->prepare<component_t>();
// ^^^^^^^^^^^^^
// Perform component execution ... here I just print the id of the component
std::cout << x->id() << "\n";
// After processing component_mgr recycle() and / or dispose() are called
delete x;
});
}
Putting it all together, a typical controller usage would look like this:
controller c(/* some initialization parameters */);
result = c->process<component_a, component_c>(/* some more parameters */);
That would be my preferred way of usage, passing the components as variadic template arguments. Within the controller process method, these component types are iterated and executed. I would really like to pass the components with the process method and not with the controller instantiation.
My basic problem relies in component managers prepare method. A simple implementation of a component_manager and its prepare method would look like this:
T* prepare(/*...*/)
{
return new T(); // Create component instance
}
However, I will have different implementations of component managers, for example, I would like to recycle and reuse the created component pointers by using an object pool. In such case I may have something like
return borrow_object<T>(/* some key */); // Get from pool, will be returned back to pool with `recycle`...
A the end I will have various distinct component_managers and each implementation of prepare and the other recycle/disposal methods will differ, however, for all cases I need the component type T. But ... a template method cannot be virtual. I am aware of this!
Is there any way to fix the above problem or perhaps a way better approach or design for this problem? I been sitting and staring at this too long, so please bear with me if I missed something really simple.
Thanks for your time!
I'm not an expert of inheritance and virtual methods... and I'm not sure to understand your exact requirements... anyway, as you said, a template method cannot be virtual.
So you have to take in count this.
But a template method can call a virtual method in a template class.
So I propose to make virtual prepare() in iprocessing_component_manager to return a icomponent pointer.
struct iprocessing_component_manager
{
virtual ~iprocessing_component_manager () = default;
virtual icomponent * prepare () = 0;
};
Next, to prepare a single type template derived class that implement prepare()
template <typename T>
struct type_processing_component_manager
: public iprocessing_component_manager
{
virtual ~type_processing_component_manager () = default;
virtual T* prepare () override
{ return new T; }
};
Observe that prepare() return a pointer to T, not a pointer to icomponent.
Now you can write a variadic template tuple_processing_component_manager, that inherit from all type_processing_component_manager<Ts>, with a template (not virtual, obviously) prepare() that call the right (type dependent) virtual inherited prepare() method.
template <typename ... Ts>
struct tuple_processing_component_manager
: public type_processing_component_manager<Ts>...
{
virtual ~tuple_processing_component_manager () = default;
template <typename T>
T * prepare ()
{ return type_processing_component_manager<T>::prepare(); }
};
In the main process() you can have a component_mgr based over the variadic processing component manager
auto component_mgr
{ std::make_unique<tuple_processing_component_manager<Ts...>>() };
and use it, in the lambda, as follows
using component_t
= typename std::remove_reference<decltype(comp)>::type;
std::unique_ptr<component_t> x
{ component_mgr->template prepare<component_t>() };
std::cout << x->id() << "\n";
The following is a full working example.
#include <tuple>
#include <memory>
#include <utility>
#include <iostream>
namespace detail
{
template <typename Tuple, typename F, std::size_t ... Is>
constexpr void for_each_impl (Tuple && tuple, F && f,
std::index_sequence<Is...>)
{
using swallow = int[];
(void)swallow { 1,
((void)f(std::get<Is>(std::forward<Tuple>(tuple))), 0)... };
}
}
template <typename Tuple, typename F>
constexpr void for_each (Tuple && tuple, F && f)
{
constexpr auto N
{ std::tuple_size<std::remove_reference_t<Tuple>>::value };
detail::for_each_impl(std::forward<Tuple>(tuple), std::forward<F>(f),
std::make_index_sequence<N>{});
}
struct icomponent
{
virtual ~icomponent () = default;
virtual std::string id () = 0;
};
struct component_a : public icomponent
{ virtual std::string id () override { return "component a"; } };
struct component_b : public icomponent
{ virtual std::string id () override { return "component b"; } };
struct component_c : public icomponent
{ virtual std::string id () override { return "component c"; } };
struct iprocessing_component_manager
{
virtual ~iprocessing_component_manager () = default;
virtual icomponent * prepare () = 0;
};
template <typename T>
struct type_processing_component_manager
: public iprocessing_component_manager
{
virtual ~type_processing_component_manager () = default;
virtual T* prepare () override
{ return new T; }
};
template <typename ... Ts>
struct tuple_processing_component_manager
: public type_processing_component_manager<Ts>...
{
virtual ~tuple_processing_component_manager () = default;
template <typename T>
T * prepare ()
{ return type_processing_component_manager<T>::prepare(); }
};
template <typename ... Ts>
void process ()
{
auto component_mgr
{ std::make_unique<tuple_processing_component_manager<Ts...>>() };
std::tuple<Ts...> components;
for_each(components, [&](auto& comp)
{
using component_t
= typename std::remove_reference<decltype(comp)>::type;
std::unique_ptr<component_t> x
{ component_mgr->template prepare<component_t>() };
std::cout << x->id() << "\n";
});
}
int main ()
{
process<component_a, component_b, component_c>();
}
If you're not interested in the std::tuple of components, and in for_each() processing, you can use directly the type_processing_component_manager struct in a recursive process()
// ground case
template <int = 0>
void process ()
{ }
// recursive case
template <typename T0, typename ... Ts>
void process ()
{
type_processing_component_manager<T0> component_mgr;
std::unique_ptr<T0> x { component_mgr.prepare() };
std::cout << x->id() << "\n";
// recursion
process<Ts...>();
}

Template a virtual method from base class instead of use overloading

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*/}
};

c++ container of inherited class types

I want to have a container (let's say an std::vector) that would hold various inherited types, and would instantiate them,.i.e. vector of classes --> vector of objects.
For instance:
class A{};
class B: public class A
{};
class C: public class A
{};
void main()
{
std::vector<of inherited A types> typesVec;
std::vector<A*> objectsVec;
typesVec.push_back(class B);
typesVec.push_back(class C);
for (int i = 0; i < typesVec.size(); i++)
{
A* pA = new typesVec.at(i);
objectsVec.push_back(pA);
}
}
Thanks in advance..
This isn't possible in C++ (at least not directly). I can see this happening in a language that has reflection, but C++ doesn't.
What you can do instead is create a factory or simply methods that create objects of the specified type.
Instead of having a vector of types, you'd have a vector of object generators (close enough, right?):
class A{};
class B: public class A
{};
class C: public class A
{};
struct AFactory
{
virtual A* create() { return new A; }
};
struct BFactory : AFactory
{
virtual A* create() { return new B; }
};
struct CFactory : AFactory
{
virtual A* create() { return new C; }
};
//...
typesVec.push_back(new BFactory);
typesVec.push_back(new CFactory);
for (int i = 0; i < typesVec.size(); i++)
{
A* pA = typesVec.at(i)->create();
objectsVec.push_back(pA);
}
There is a reusable approach with templates. This is a generic factory for derived types that comes with an install and a create method which lets you write code like this:
int main() {
TypeVector<Base> t;
t.install<Foo>("Foo");
t.install<Bar>("Bar");
t.create("Foo")->hello();
}
Note it's a sketch implementation. In the real world, you may provide another template parameter to specify the underlying container type (for few types, vector is probably more efficient than set).
The type-vector is this:
template <typename Base>
class Creator;
template <typename Base>
class TypeVector {
public:
template <typename Derived>
void install (std::string const &name) ;
std::shared_ptr<Base> create (std::string const &name) const;
private:
struct Meta {
Meta(std::shared_ptr<Creator<Base>> creator, std::string const &name)
: creator(creator), name(name) {}
std::shared_ptr<Creator<Base>> creator;
std::string name;
};
std::vector<Meta> creators_;
};
We somehow need a way to store the type in an allocatable manner. We do it like boost::shared_ptr, which combines an abstract base class and a template derived class:
template <typename Base>
class Creator {
public:
virtual ~Creator() {}
virtual std::shared_ptr<Base> create() const = 0;
};
template <typename Base, typename Derived>
class ConcreteCreator : public Creator<Base> {
public:
virtual std::shared_ptr<Base> create() const {
return std::shared_ptr<Base>{new Derived()};
}
};
The "concrete creator" is able to allocate an actual object, and return a pointer-to-base of it.
Finally, here are the implementations of TypeVector::install and TypeVector::create:
template <typename Base>
template <typename Derived>
void
TypeVector<Base>::install (std::string const &name)
{
creators_.emplace_back(
std::shared_ptr<Creator<Base>>(new ConcreteCreator<Base, Derived>()),
name);
}
template <typename Base>
std::shared_ptr<Base>
TypeVector<Base>::create (std::string const &name) const
{
for (auto m : creators_) {
if (name == m.name) return m.creator->create();
}
throw std::runtime_error("...");
}
and finally, here's a test:
#include <iostream>
struct Base {
virtual ~Base() {}
virtual void hello() const = 0;
};
struct Foo : Base {
virtual void hello() const { std::cout << "I am a Foo\n"; }
};
struct Bar : Base {
virtual void hello() const { std::cout << "I am a Bar\n"; }
};
int main() {
TypeVector<Base> t;
t.install<Foo>("Foo");
t.install<Bar>("Bar");
t.create("Foo")->hello();
}
You can go further and make any constructor callable for code like ...
...
Bar(Color, Age, int)
...
t.create("Foo", Color::Red, Age::TooOld, 42)
... but this requires an awesome grasp of variadic template argument lists, and how to fold them into a constructor call (can be done and has been done, but it would explode this answer).
Just a quick solution sketch:
The C++ standard does not provide direct calls to constructors. As such you can't have function pointers to constructors; you can, however, have a wrapper function "create", something like:
template<typename T>
T* create () {
return (new T();
}
Provide overloaded create definitions for one argument, two arguments, ... or try to use variadic templates; or, if you already know what types you need, you can create the create functions specifically. Then you can have a function pointer to the create function:
&create<TheType>
Mind that the signature of this function however depends on the type used. You can however create a struct that contains typdefs for the templated type, a typedef for the type pointer, and the create function as a functor operator().
Thus you can have two vectors, one for the function pointers to the create function, or, alternatively to the structs mentioned before, and one with the actual objects. In your case where you only have inherited types, you might be able to define functions A* createB() { return new B(); }, A* createC() { return new C(); }, ... for each inherited type B, C, ... and have a vector for pointers to these create functions and the second vector for the A pointers.
I might point you Andrei Alesandrescu´s book Modern C++ Design (or the Loki library he describes in the book) and the chapter about type lists. This would require you to do the typeVec.insert( type ) at compile time.

C++ interface style programming. Need a way out

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;
}