Vector template question - c++

Question as I have not done much with vectors and templates.
If I have a class foo that is templated class and I want to create a vector of foo pointers regardless of foo type, what would the syntax look like?

There is no direct way to do this. Different instantiations of the same template are treated as distinct classes with no relation to one another.
If you want to treat them uniformly, one option is to create a base class that the template foo class then inherits from. For example:
class foo_base {
/* ... */
};
template <typename T> class foo: public foo_base {
/* ... */
};
Now, you can create a vector<foo_base*> to store pointers to foo_base objects, which are in turn all specializations of foo.

You wouldn't. Every instantiation of the class template foo (e.g. foo<int>, foo<char> etc) is a distinct type. foo itself is not a type.
You'd need some base class for them and store pointers, making use of polymorphism.

Not possible. When you use a class template anywhere, you need it instantiated on a type.
One possibility to circumvent that, is to provide a polymorphic interface base class for foo and have a vector of those pointers.
class IFoo{
virtual void bar() = 0;
virtual int baz() = 0;
};
template<class T>
class Foo : IFoo{
// concrete implementations for bar and baz
};
// somewhere in your code:
std::vector<IFoo*> vecFoo.
vecFoo.push_back(new Foo<int>);
The obvious problem with that is, that you can't need to know each possible return value for your bar and baz functions.

You cannot have a vector of foo<?>. The compiler when it creates the vector needs to know precisely what type it stores because every instantiation of foo<?> could potentially have a different size and entirely different members (because you can provide explicit and partial specializations).
You need to give the foo<T> a common base class and then put baseclass pointers into the vector (preferably using shared_ptr or something similar).
As an alternative there are ready classes that hide this from you and act like a container of references. Among them is boost::ptr_vector, which however also need a common type to store.
class common_base {
/* functions to access the non-templates parts of a foo<T> .. */
};
template<typename T> class foo : public common_base { };

If you are trying to emulate concept: "vector of pointers to Foo" without specifying T, you are trying to emulate template typedefs that are not supported by current standard.
The workaround is
template <class T>
my_vector
{
typedef std::vector<Foo<T>*> type;
}
If, instead, you can afford polymorphic interface for your Foo guy, I would do that as it was already suggested.

Related

C++ list of unspecialized template type objects?

I've looked for questions on this subject, and although there are similar ones, none really address my question. So, here I go.
Suppose I have a template type F, and I declare a series of specializations as member variables of another object:
F<A> a;
F<B> b;
.
.
.
Later, I'd like to iterate over these and perform an operation that is defined on any F instance.
So my impulse is to create a std::list< F> but this does not work.
Is there a way to create a list of objects of type F, that is, without specifying the template parameter?
My hunch is no, not in C++, but hoping I am wrong.
Unless all F<X> derive from some common base-class independent of X, this is only be possible using type erasure or heterogeneous containers.
If they all inherit from Foo, then of course you can iterate over them as as Foo&/Foo*, but I guess you knew that.
If they have different types the standard-containers cannot hold them, because they are homogeneous - all elements have the same type. There is probably some library with heterogeneous containers, but in the STL, you can only emulate this with std::variant or std::any.
The last way I could imagine this works out - I don't recommend this - is by creating the enclosing class as a derived class of the F<X>s (variadic template) and encoding the invocations into the hierarchy, s.t. every Fsfoo` is called
Since this is somewhat more involved here is a sample:
#include <iostream>
template <class X>
class Foo {
X mem;
public:
explicit Foo(X arg) : mem(arg) {}
void foo() {
std::cout << mem;
}
};
template <class X, class ...Xs> class Holder;
template <class X>
class Holder<X> {
X member;
public:
Holder(X arg) : member(std::forward<decltype(arg)>(arg)) {}
void call() {
member.foo();
}
};
template <class X, class ...Ys>
class Holder : public Holder<Ys...> {
X member;
public:
Holder(X arg, Ys ...args) : Holder<Ys...>(std::forward<decltype(args)>(args)...), member(std::forward<decltype(arg)>(arg)) { }
void call() {
member.foo();
Holder<Ys...>::call();
}
};
int main() {
// omitting the template-args requires c++17 deduction guides
Holder holder(Foo(4), Foo(" Hello "), Foo(7L), Foo(" World "));
holder.call();
std::cout << std::endl;
}
You maybe able to guess, that this is typically not what you want, because it is super-complex. I actually omitted some things like perfectly forwarding the arguments to keep it somewhat minimal, s.t. one can hopefully understand the concept.
Unfortunately, the answer is NO. In C++ you can't have a container of heterogeneous unrelated objects, and different instantiations of the same template are unrelated.
The only way to make it work is to use some form of the type erasure. The most idiomatic is to use inheritance and virtual functions, and put pointers to base object into your list.
As far as C++ is concerned, two different template instantiations of a template class or struct are completely separate types and have no relation to each other whatsoever. For example, a std::vector<int> and a std::vector<char> are separate types; neither derives from the other or from any common base. The fact that both types arose from instantiations of the same template does not create a semantic relationship between the types. In that sense (and that sense only) you might think of templates like preprocessor macros which are expanded before compilation to declare new and unrelated types.
But, you can create such a relationship yourself using inheritance, just as you would with any non-template types:
#include <iostream>
struct foo_base {
virtual void print() = 0;
};
template <typename T>
struct foo : foo_base {
foo(T data) : data(data) {}
virtual void print() override {
std::cout << data << std::endl;
}
private: T data;
};
void example() {
foo<int> f(42);
f.print();
}
Here, a foo<int> and a foo<char> are separate types (as distinct instantiations of the foo<> template), but all foo<> instantiations derive from foo_base. (Unless, of course, you provide an explicit specialization of foo<> which does not derive from foo_base...)

C++: Containers of Arbitrary Template Type

In C++, suppose I have a templatized class, like
template <typename T>
class Foo
{
...
};
and suppose that I have several kinds of Foo objects, like
Foo<int> intFoo = Foo<int>();
Foo<double> doubleFoo = Foo<double>();
...
and so on.
Actually, its worse than that. I really want an intFoo object of a class that inherits from Foo< int >, for instance.
I would like to do something like this:
std::vector<Foo<?> > aVector;
aVector.push_back(intFoo);
aVector.push_back(doubleFoo);
Keeping in mind that I have substantially oversimplified my design case, is there a simple way to do this?
A solution would be to have your Foo inheriting from an empty base class
struct CommonBase {};
template<typename T>
class Foo : public CommonBase
{
// ...
};
and then have a container of pointers to the common base
vector<CommonBase*> v;
If you want to keep away from inheritance, you could use boost:any to store any type in your container.
An interesting topic to look into (if you want to manually implement this kind of things) is type erasure
Foo<int> and Foo<double> are 2 different classes despite they share the name Foo, so you can't just put them to vector as is. But you can use boost::variant and store a vector of variants.

CRTP intermediate class that needs to also be made final

I have an inheritance chain of CRTP classes. The CRTP classes derive from each other, until a 'final' derived class passes itself as the CRTP parameter and finalizes the inheritance chain.
template <class W>
struct Base
{
.....
};
template <class W>
struct Derived_inheritable: public Base<W>
{
....
}
template <class W>
struct Derived2_inheritable: public Derived_inheritable<W>
{
....
}
...
What I want to do is to be able to have such 'final' end-user classes at each level of the CRTP inheritance chain, that involve no templates:
typedef Derived1_inheritable<Derived1> Derived1;
As you can guess, this typedef does not work, because it references its own type being defined. The question is how to achieve this?
The way I could think of, is:
struct Derived1: public Derived1_inheritable<Derived1>
{
//not convenient, need to redefine at least a forwarding constructor
}
As the comment in the code says, this is not a very elegant solution - I need to redefine the constructor to forward to the base constructor. Does anyone know a more elegant way?
typedef Derived1_inheritable Derived1;
That line makes no sense, the argument to the template is a type but you are trying to pass a template (incidentally the same template that you are instantiating, but besides that extra quirk the fact is that your template takes a type as argument and you are passing a non-type)
It is not really clear from the question what you are trying to achieve. You should work on stating your goal rather than your approach to solving that goal.
I want to make a "final" class for each DerivedX_inheritable that is non-template and passes itself as the W parameter.
That is exactly done in the code that you produded:
struct Derived1: public Derived1_inheritable<Derived1> {}
which is a type definition (make a "final" class). The fact that your CRTP bases require arguments that must be provided by the end user and the need of the forwarding constructor thereof is just a side effect of your design.
I think I found an elegant solution:
template <class W>
struct Base
{
.....
};
template <class W>
struct Derived_inheritable: public Base<W>
{
....
}
//solution
struct Derived2_dummy;
template <class W=derived2d_ummy>
struct Derived2_inheritable: public Derived_inheritable<W>
{
....
}
struct derived2_dummy: public: Derived_inheritable<>{};
typedef Derived2_inheritable<> Derived2;

Passing a template class as an argument to a function

If I define a class using a template such as
template<class K, class V>
class myclass {
...
};
is there a way to pass objects defined by myclass to functions without using a template for the function? In order words, for every function that accepts myclass objects, does it also need to be defined using template< class K, class V> ?
The main reason for this is that I would like define a set of static functions that act on myclass objects so that I may limit the scope of these functions within their cpp files and not in header files.
Make your template class inherit from some base class:
template<class K, class V>
class myclass : mybaseclass { ... };
where the base class declares the public functionality of the template as pure virtual. This way you only have one function rather than one function for each K, V combination.
No, you cannot. A class template is not a class -- it is only a template. Only once you plug in the template parameters do you get a type, and for each different set of parameters you get a different, unrelated type.
Perhaps it's feasible for you to run some sort of type-erasing scheme, whereby you have a single container class which contains an abstract member pointer, and for each type you instantiate a concrete derived object. (Check out Boost.any.)
A bit like this:
class MyClassHolder { };
template <typename K, typename V>
class MyClassConcrete { };
class MyClass
{
MyClassHolder * p;
public:
template <typename K, typename V> init(...) // could be a constructor
{
p = new MyClassConcrete<K, V>();
}
};
Now you can make your function accept a MyClass, but you have to add enough virtual functions to MyClassHolder, implement them in MyClassConcrete and expose them in MyClass that you can realise all your desired semantics.
Yes, if you want your functions to be able to accept any instantiation of your template class they too must be template (typically with the same template parameters that are used for the class).
On the other hand, you can have your template class inherit from a non-template class that still allows you to operate the derived class via virtual functions. Also, to hide the type of your class and avoid riddling all your code of templates, there are the several techniques of type erasure.
No, you will have to make the functions templated as well (unless of course they will be limited to only working with a specific specialization of myclass).
You could do this:
void myfunc(const myclass<int, int>& mc) {}
Only if you wanted to be able to pass any type to your myclass argument in your function, would you need to make that myfunc a template too.
Due to C++'s static nature, you must instantiate a copy of the function for each (K, V) pair in the source since the compiler will have to generate code to access each pair's members differently.
While your reason is not entirely clear to me, yes, each function that takes a myclass as a parameter will also have to be templated on K and V. If you manage to abstract the basics, you could have each myclass< K, V > (which is a different type for each combination of K and V) inherit from a single base class that implements the functionality, or forwards it through virtual functions.

How to declare data members that are objects of any type in a class

In this piece I'm trying to declare in Class B a list that can hold objects of Class A of any type, such as A<int>, A<double>, A<float>. I intend to add A objects to the list during runtime:
#include <list>
template <class T> class A {};
class B {
template<class T> std::list<A<T>*> objects;
};
It seems like making a list like this should work but compiling it gives an error:
Line 6: error: data member 'objects' cannot be a member template
compilation terminated due to -Wfatal-errors.
Can somebody explain why this doesn't work and how I can fix it?
That's just not how C++ works. If you want to group different objects together, they need to have at least some relation. Being instantiations of the same class template doesn't imply that they are related, they're completely distinct types. If you want a list of A<T>*s, better make a list of base-class pointers and forward operations through virtual functions:
class A_base{
public:
virtual void foo() = 0;
virtual ~A_base() { }
};
template<class T>
class A : public A_base{
public:
void foo(){
// ...
}
};
class B{
std::list<A_base*> objects;
};
Member variables aren't allowed to be templates. Only member functions can be templates. You'll have to templatize the enclosing class B instead:
template <class T>
class B {
std::list<A<T>*> objects;
};
Unfortunately you cannot have template variables. Only option to declare a member data is to make the class template:
template<class T>
class B {
std::list<A<T>*> objects;
};
Depending on what you're doing, type erasure might be an option. On the Tension Between Object-Oriented and Generic Programming in C++ is my favorite write-up on the subject.
In a nutshell, you convert the static dispatch enabled by the templates into dynamic dispatch through a custom inheritance tree you setup on the fly. Instead of storing A<T>, you create a new type that has the common interface you desire, and using some template/inhertiance voodoo this new type stores an A<T> without actually exposing the T. So A<int> and A<double> and A<A<std::list<A<int> > > > and some_type_that_looks_like_A_but_really_isnt all reduce down to a single type.
But you have to have a common interface, independant of that parameter. If you can't, things get more difficult.
Boost.Any is a good example, as is std::shared_ptr [which uses type erasure to remember how to delete the pointer passed to it even in the face of non-polymorphic inheritance].
Make B class template just like you've made A a class template:
template<class T>
class B {
std::list<A<T>*> objects;
};