Passing template classes as arguments to methods - c++

I have a class method with a signature like this:
// someheader.h
class Blah {
...
void DoSomeWork(class Screen& p);
..
};
The Screen class however is supposed to turn into a template now, something like...
template <int width, int height>
class Screen {
...
So my question is, how should I change the method's prototype in someheader.h?

Screen isn't a defined type, there is only a Screen<int,int>.
As you are expecting a templated type as a parameter you need to make it a function template. With that you can name the parameter type:
class Blah
{
public:
template<int width, int height>
void DoSomeWork(Screen<width,height>& p);
};

As DoSomeWork already existed before Screen was a template, it probably does not need to know that Screen is now a template. You could thus have a ScreenBase class that defines the API that DoSomeWork needs, and Screen inherits from this:
class ScreenBase { ... };
class Blah {
DoSomeWork(const ScreenBase& s) { ... }
};
template <int width, int height>
class Screen : public ScreenBase
{
...
};

Sometimes it's easiest to just define template functions to deal with parameters that are templatized types. Of course, this means that the implementations of those functions need to move to the header files, which can sometimes be a problem.
One alternative is to define an abstract base class and derive the template class from it, then use a pointer or reference to the abstract interface in function signatures.
class IScreenBase
{
virtual void DoSomeWork() = 0;
};
class Blah
{
DoSomeWork(IScreenBase& s) { s.DoSomeWork(); }
};
template <typename T>
class Screen : public IScreenBase
{
virtual void DoSomeWork() { ... }
};
Screen<Foo> s;
Blah blah;
blah.DoSomeWork(s);

Related

Getting template type from inherited class C++

So I'm trying to populate a custom collection of a class that is inherited from a template class, like so
template<typename T>
class Parent {
public:
T value;
Parent(T val) {value = val;}
}
class ChildA : Parent<int> {
...
}
class ChildB : Parent<double> {
...
}
// ==== Collections ====
template<typename cT>
class ParentCollection {
public:
cT list[10];
}
class ACollection : ParentCollection<ChildA> {
...
}
class BCollection : ParentCollection<ChildB> {
...
}
So I want to add a function to ParentCollection that will allow me to generate and add a new cT type the the list array. This should be inherited by the children. If I was to write this in ACollection or BCollection, it would be something like:
void ACollection::Add(int val) {...}
or
void BCollection::Add(double val) {...}
respectively. However, since these both do the exact same thing except generate different Childrens, I would want to write this in the ParentCollection, but I can't figure out how to do something like:
void ParentCollection::Add(T val) {...}
that is, use the T type from the Parent class template in the parms for ParentCollection. Is something like this possible? Or must I write the add functions separately for both child collections.
Usually it's a good idea to expose the template parameters, because since C++ has no reflection capabilities it's otherwise a hassle to obtain them outside of the class itself:
// inside parent class
using value_type = T;
You can then reference this typedef to specify your member function signature:
void Add(typename cT::value_type val)
You can typedef the T type in the parent class and then use it in a derived class:
template <typename T>
class Base
{
public:
typedef T BaseT;
};
class Derived : public Base<int>
{
public:
static void printBaseType()
{
printf("%s\n", typeid(BaseT).name()); // prints "i"
}
};
Specific instructions for fixing this:
In the Parent class, add: typedef T ParentT
You can then use the type ChildA::ParentT (int) or ChildB::ParentT (double)
In the ParentCollection class, you can expose this again by doing: typedef typename cT::ParentT ParentT
In ACollection, you can then access it as ParentT.
In ParentCollection, you can write the function declaration as: void Add(ParentT val);
The function definition, however, needs to qualify the ParentT type because you are outside of the class scope, so you write: void ParentCollection::Add(ParentCollection::ParentT val) { ... }

Way to call a static method of a class template without specifying an instantiation?

Is there any way to define a static method in a class template which can be then be called without specifying the instantiation?
I think this could be useful in cases where you have some auxiliary static function, which logically belongs in a class (which happens to be a template one), but doesn't depend on the template parameter.
I don't mind either:
Having the same static method (including address and all) for all
instantiations, or
Having a separate static method for each instantiation, but be able to call the static method without
specifying an instantiation where I call the method (some default
would be called).
e.g.
template<typename T> class C {
public:
static int func() { return 0; }
};
int main()
{
// This works.
return C<int>::func();
// These don't work.
// return C<>::func();
// return C::func();
}
The simplest solution is probably to have the static function belong in a base class, and then the template derives from the base:
struct CBase {
static int func() { return 0; }
};
template<typename T> class C : public CBase {
public:
};
int main()
{
// This works.
return C<int>::func();
// This will work too:
return CBase::func();
}
You can use inheritance which will also remove the duplication of any non static functions ( that also don't care about the template type ) in your binary, i.e:
class A {
public:
static int func() { return 0; }
};
template<typename T>
class B : A {
};
If you want to get C or C<> to work you can either rely on a base non-template class that contains the given function or use template specializations as it follows:
template<typename...>
struct C;
template<>
struct C<> {
static int func() { return 0; }
};
template<typename T>
struct C<T>: C<> {
// all the other things around...
};
int main() {
C<int>::func();
C<>::func();
}
For you don't provide a definition for the primary template, accepted specializations are:
C<> that contains only the given function
C<T> that accepts only a parameter as it was in the original example
See it on wandbox.
If you can't use variadic templates, you can still do something similar with a custom type.
As an example:
struct func_only {};
template<typename T = func_only>
struct C;
template<>
struct C<func_only> {
static int func() { return 0; }
};
template<typename T>
struct C: C<func_only> {
// all the other things around...
};
int main() {
C<int>::func();
C<>::func();
}
That being said, make it a free function looks to me as the best solution anyway.
How would that work? You typically depend on the type in your static functions too.
template<typename T> class C {
public:
static int func() { return sizeof(T); }
};
If they do not depend on it, you should probably make them free functions, or static members of a base class of this class.

c++ template problem

i have a class which has a template by other purposes:
template<class t>
class MyClass {
public: //of course public...
t foo;
std::string text;
}
and i have another class which method get all kind of these class through the arguments, and want to store the pointer in an array. The class dont want to access the specific (tempalted) parts of the classes only the common attributes/methods.
class Container {
public: //of course public...
MyClass* array; //this is allocated with some magic.
void bar(MyClass& m) {
and want to store the class in a MyClass* array.
}
}
here is the error that argument list for template missing
how can i solve this?
The simplest method would be to make that function a template as well:
template <class t>
void bar(MyClass<t>& m) {
// ...
}
Note that that should probably be const MyClass<t>&, because you don't need to modify it.
Your new code is meaningless. There is no such that as an object of type MyClass, because MyClass is a template. If you want to operate on these classes irrespective of their template argument, then you need to factor out the non-template portions as a base class:
class MyClassBase
{
public:
// polymorphic base classes should always have virtual destructors
~MyClassBase() {}
virtual void some_function() = 0;
};
template <typename T>
class MyClass : public MyClassBase
{
public:
// implement abstract functions
void some_function()
{
// template argument T is available here
}
};
Then you can refer to that base, and when you call a virtual function it will dynamically dispatch:
class Container
{
public:
// no magic: use a std::vector for dynamic arrays
std::vector<MyClassBase*> array; // not by value! avoid slicing
void bar(MyClassBase& m)
{
array.push_back(&m);
}
void baz()
{
array[0]->some_function(); // for example
}
};
How about putting a common base class.
class MyClassCommon {
protected:
~MyClassCommon() { }
public:
std::string text;
};
template<class t>
class MyClass : public MyClassCommon {
public: // of course public...
t foo;
};
class Container {
public: // of course public...
MyClassCommon* array; // this is allocated with some magic.
void bar(MyClassCommon& m) {
/* ... */
}
};
If you want to create a "multi-template" array, you'd better use a non-template class as a base class of a template class. Or you can make a template array and store any objects in it.
the text variable in your class is private so unless you bar function is a method of the class you can't legally use it like that

class containing a generic type of a child

Is there any possible way that a generic type can be used to contain a child of a base class.
From the assignment given to me, I am to create something similar to the following in structure.
template <class T>
class Fruit {
private:
int count;
int location_id;
T type;
public:
virtual void displayInfo();
};
class Apple : private Fruit<Apple> {
private:
int variety;
public:
void displayInfo() {
printf("Location %i has %i of %s in stock", location_id, count, variety);
}
};
Fruit<Apple> appleinventory[SIZE];
Basically, I think you can't have a template generic type be the same as a derived class. Am I wrong? Is there something similar that would possibly work?
Update:
For the assignment, I believe we are to use inheritance to show use of virtual functions. I've updated the code above. I think this would work, but does NOT need templates to be successful. We have not covered any advanced, redundant inheritance methods in class.
This is perfectly fine, in principle.
Read up about Curiously Recurring Template Pattern (CRTP) for more info on usage of derived class as the instantiating type in a class template that is its base, esp the example about static polymorphism which should look 'curiously' familiar.
template <class Derived> struct Base
{
void interface()
{
// ...
static_cast<Derived*>(this)->implementation();
// ...
}
static void static_func()
{
// ...
Derived::static_sub_func();
// ...
}
};
struct Derived : Base<Derived>
{
void implementation();
static void static_sub_func();
};
Ignoring questions of why you want to do this....you can get some of the way by doing this following:
template <class T> class Fruit
{
private:
int count;
int location_id;
T* type;
};
class Apple : private Fruit<Apple>
{
private:
int seeds;
bool red;
};
Fruit<Apple> appleinventory[SIZE];
Note the T* type is now a pointer to Apple rather than an instance of Apple.

Overriding a templated class function

I'm trying to create some kind of callback for a class template. The code is like this:
template <typename t>
class Foo {
void add(T *t) {
prinf('do some template stuff');
on_added(t);
}
void on_added(T *t) { }
}
struct aaa {}
class Bar : Foo<aaa> {
void on_added(aaa *object) {
printf("on added called on Bar");
}
}
the on_added function on Bar never gets called. What would be the best way to add a callback that a template subclass could optionally override? Thanks
Use 'virtual'...
template <typename t>
class Foo {
void add(T *t) {
prinf('do some template stuff');
on_added(t);
}
virtual void on_added(T *t) { }
}
struct aaa {}
class Bar : Foo<aaa> {
void on_added(aaa *object) {
printf("on added called on Bar");
}
}
Your on_added function in Foo needs to be virtual.
You have to make the function virtual if you want calls in the base class to use the implementation in the derived class:
template <typename t>
class Foo {
...
virtual void on_added(T *t) { }
};
Note that this is not special to templates, but applies to all classes.
Everyone else has already answered the question. Let me just add that adding virtual functions breaks backward compatibility of the class. So, if this is a class that you control and there are no other dependent classes, then yes you can go ahead and convert the on_added to virtual, if not you need to make sure that the dependent modules are also rebuilt.