C++ class template for similar classes - c++

I have a socket data type class that is used to read and parse a value from socket stream (may be used for file too).
Let my class be mc_double:
class mc_double {
private:
double value;
public:
bool read(socket);
write(double);
}
Actual class is more complicated, but this is the principle. Now, I need to parse float from the stream. Float is way similar to double, so is already implemented int. Could't I merge this class definitions, with all double, int and float somehow templated?
This is what I mean:
class mc_<typename = double or int or float> {
private:
typename value;
public:
bool read(socket);
write(typename);
}
Some methods would be then defined individualy as mc_double::method() others would be same for all types: mc_typename::general_method(). Also, for some I'd need just minor changes in code:
typename mc_typename::return_value() {
return val;
}
Or the constructor:
mc_typename::mc_typename(<int, long, char, double> number) {
val = (typename)number;
}
The result should be three classes - mc_int, mc_float and mc_double.
I have found the official C++ template docs, but I only figured out the last part of my question - I can create a function that accepts multiple data types. The rest does not seem to be that easy.

You could make your class a class template:
template<typename T, bool base = true>
class mc {
protected:
T value;
public:
bool read(socket);
write(T);
};
This class will contain the member function that are common for all types T. Then, you could specialize this class templates separately for different types and let them inherit from mc<T, true>:
template<>
class mc<double, true> : public mc<double, false> {
public:
// Member functions for double only...
};
template<>
class mc<int, true> : public mc<int, false> {
public:
// Member functions for int only...
};
Make sure the non-public member data of the primary class template are made protected if you want derived classes to access them.
You could then instantiate them this way:
mc<double> m;
mc<int> m;
// ...
If you really want to use the mc_double and mc_int names, then you could either:
a) Create type aliases for them:
typedef mc<double> mc_double;
typedef mc<int> mc_int;
b) Change the design of the class template to not use specialization and have one single template parameter, and create the derived classes independently:
template<typename T>
class mc {
protected:
T value;
public:
bool read(socket);
write(T);
};
class mc_double : public mc<double> {
public:
// Member functions for double only...
};
class mc_int: public mc<int> {
public:
// Member functions for int only...
};

You could use templates in the class definition as follows:
template <typename T>
class mc
{
public:
bool write(T _val);
private:
T mVal;
};
but you can't as easily specialize some methods but not others based on the type of T (i.e., you have to specialize the entire class, not just one method). You could solve this with some sort of inheritance hierarchy, where methods that are the same regardless of the type are in the base, and the specialization is in derived classes. So keep the above (assuming write is one that doesn't change) and create:
class mc_double : public mc<double>
{
public:
void doSomethingSpecific() { /* code specific for 'doubles' */ }
};

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) { ... }

c++ abstract base with datatype will be defined in derived class

I want to have a base class with datatypes that will be defined in derived class.
pseudo code
class Base{
public:
void Enroll(vector<int> v){
feature_list.emplace_back(ExtractFeature1(v));
}
vector<double> Compare(vector<int> v){
FeatureType2 ft2 = ExtractFeature2(v);
vector<double> scores;
for (auto &ft1:feature_list){
scores.emplace_back(Compare(ft1, ft2));
}
return scores;
}
protected:
vector<FeatureType1> feature_list;
virtual FeatureType1 ExtractFeature1(vector<int> v)=0;
virtual FeatureType2 ExtractFeature2(vector<int> v)=0;
virtual double Compare(FeatureType1 f1,FeatureType2 f2)=0;
}
So each derived class will implement a different way of extracting and comparing features.
I don't know how to do set some kinds of placeholder type for FeatureType1 and FeatureType2 in Base class and then force Derived class to define them. Any advice or guidance would be greatly appreciated.
I want to have a base class with datatypes that will be defined in derived class.
Well, you can't quite do that: The base class has to be completely defined for you to derive classes from it.
What you can do, however, is use the Curiously-Recurring Template Pattern (CRTP):
template <typename T>
class Base {
using data_type = typename T::data_type;
// this will be a different type for each T - and
// we don't need to know it in advance
void Enroll(const vector<int>& v){
// implementation that can depend on T in many ways.
// Specifically, you can use `data_type`.
}
vector<double> Compare(const vector<int>& v){ /* ... */ }
// ...
};
class SomeDerived : Base<SomeDerived> { /* ... */ };
class AnotherDerived : Base<AnotherDerived> { /* ... */ };
The classes SomeDerived and AnotherDerived don't actually have the same base class, but their base classes are instantiations of the same template, so you avoid code duplication. And - you have the "base" class using types defined in the derived class, as long as they're defined in the same way.
Edit (thanks #Aconcagua): You might not need to go as far as the full CRTP. If the only thing your base class needs to know regarding the derived class is the data type, then just template the base class on that, i.e.
template <typename DataType>
class Base {
using data_type = DataType;
// ... as before...
};
class SomeDerived : Base<some_data_type> { /* ... */ };
class AnotherDerived : Base<another_data_type> { /* ... */ };

Using template argument of base class in derived class

Consider the following situation in C++:
template<int n>
class Base { ... };
class Derived3 : public Base<3> {
// a complicated body, making use of n=3
};
class Derived7 : public Base<7> {
// a completely different body, making use of n=7
};
Inside of the Derived3 member functions, I would like to explicitly use n=3, and inside Derived7, n=7, without hardcoding the numbers, i.e., still referring to something like a template argument n. The following options come to my mind:
Also templating the derived classes on n, and then using typedef. This way, the derived classes know n:
template<int n>
class DerivedTemplate3 : public Base<n> { ... };
typedef DerivedTemplate3<3> Derived3;
template<int n>
class DerivedTemplate7 : public Base<n> { ... };
typedef DerivedTemplate7<7> Derived7;
The problem with this is that DerivedTemplateX makes sense for nothing but n=X, so this feels like abusing the template paradigm.
Using a static const member to store n in Base, and referring to that in the derived classes:
template<int n>
class Base {
protected:
static const int nn = n;
...
};
class Derived3 : public Base<3> {
// refer to nn=3
};
class Derived7 : public Base<7> {
// refer to nn=7
};
The problem here is that I seemingly can't use the same identifier (nn vs. n). Also, I'm not sure whether this will allow me to use nn as a template argument for members of the derived classes.
So: how can this be implemented in a non-redundant, efficient way? Maybe using some kind of static const int as a member somewhere?
The standard practice is to use an uppercase letter for the template parameter, then a static const value in lowercase:
template<int N>
class Base {
protected:
static const int n = N;
...
};
Then you use the lowercase static const value n everywhere - don't use N anywhere else.
Also, I'm not sure whether this will allow me to use nn as a template argument for members of the derived classes.
It is a constant expression and so it can be used as a template argument.
Does this work for you?
template<int n>
class Base {
protected:
static const int MyN = n;
};
class Derived3 : public Base<3> {
void f()
{
std::cout << MyN;
}
};
class Derived7 : public Base<7> {
void f()
{
std::cout << MyN;
}
};
int main()
{
}

How to use policy-templates if the types of two templates are linked?

I'm currently writing a class which allows getting and setting interal program options and it should be quite flexible and easy to use.
Specifically, an option is identified by an enum type and a value type, which have a one-on-one relationship. For example, an enum IntType will contains options which have an int type.
I had in mind the following code, but have no idea how to get it working or whether I'm trying to use templates in a way i shouldn't.
enum IntType {OPTION1, OPTION2}
enum StringType { OPTION3, OPTION4}
template<class T, class T2>
class Policy{
public:
T2 getValue(const T& a);
void setValue(const std::string& name, const T2& a);
...
}
class A: public Policy<IntType, int>, public Policy<Stringtype, std::string>, ...{
...
}
Each enum constant has one associated string representation, which is constant, but options are also taken as string input into the program, so I have to be able to deduce from a string which option I should change.
But obviously, this code cannot be used to directly call set or get values without qualifying its full template specialization. So
A* a = ...
a->setValue("intoption", 5);
will not work.
Any pointers on what I should use to get this working?
A partial answer on how to derive at compile time that OPTION1 maps to int and IntType, ... would also be great.
Thanks in advance,
Broes
It is not necessary to pass both the Enum and the type. You can deduce the enum value from the type itself thanks to a traits class:
template <typename T>
struct PolicyTraits;
template <>
struct PolicyTraits<int> { static Enum const value = IntType; }
// ... and so on ...
Your selection is obviously a bit more difficult. For templates to work correctly you need selection based on compile constants, be they constants or types. This requires the names of your options to be constants.
A revised implementation would thus be:
template<class Name, class Type>
class Policy{
public:
Type getValue(Name);
void setValue(Name, Type const&);
...
}
This can be used as:
struct IntOption {};
class A: public Policy<IntOption, int> {};
int main() {
A a;
a.setValue(IntOption(), 3);
}
Also, you might be interested in looking up How Boost does it and perhaps use their library.
Since you are filling the data at runtime, templates are not viable for this design. Runtime polymorphism with virtual function will be a good choice. For example,
class Options; // Say this is the class of interest
class DataType {
public:
virtual Options& getOptions () = 0;
};
class IntType : public DataType {
public:
Options& getOptions (); // implement for 'int' type
};
class StringType : public DataType {
public:
Options& getOptions (); // implement for 'std::string' type
};
Now, class A should contain a pointer to DataType;
class A {
DataType *pData;
public:
void setValue (DataType *p) { pData = p; }
...
};
Usage:
A *a = ...;
a->setValue(new IntType); // take care of heap allocation / stack allocation

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.