How to define function with different templates as input - c++

I am completely new to C++ (and Stack Overflow), so please bear with me. I am trying to create two templates and a function that takes inputs from both templates.
I have tried to make some sample code that resembles my code, and which reproduces the error. Basically I have two templates Dog and Cat, and want to create an operator function which takes an instance of Dog and Cat respectively, but I am really struggling with how to write the function header. After having spent a lot of time reading Stack Overflow posts, I have thrown in keywords 'template' and 'typename' in an attempt to make it work, but I keep getting errors. Currently the error is
candidate template ignored: couldn't infer template argument 'T'
template <class T> class Dog
{
private:
int size;
public:
Dog(int size1)
{
size = size1;
}
};
template <class T> class Cat
{
private:
int size;
public:
Cat(int size1)
{
size = size1;
}
};
template <class T> // What to write here?
typename Cat<T>::template Cat<T> operator*(typename Dog<T>::template Dog<T> m,typename Cat<T>::template Cat<T> v)
{
Cat<int> return_cat(1);
return return_cat;
}
int main(int argc, char* argv[])
{
Cat<double>::Cat<double> new_cat(2);
Dog<double>::Dog<double> new_dog(4);
Cat<double>::Cat<double> result = new_dog*new_cat; // ERROR couldn't infer template argument 'T'
return 0;
}
My question is: How should I define the function header for the operator* function to avoid any errors?

I am not sure what you were trying to do with all the scope operators. You don't need them. Simply use the proper types. I have added const references because it looked reasonable for this scenario. They are not strictly required.
template <class T>
Cat<T> operator*(const Dog<T>& m, const Cat<T>& v)
{
Cat<T> return_cat(1);
return return_cat;
}
int main(int argc, char* argv[])
{
Cat<double> new_cat(2);
Dog<double> new_dog(4);
Cat<double> result = new_dog * new_cat;
return 0;
}

I'm not sure what your intended use of operator*() is, but generally it will look something like this:
template <class T>
Cat<T> operator*(Dog<T> m, Cat<T> v)
This allows a cat and dog to be multiplied if their template class is the same.
If they are not the same (that is, cat and dog have different types), you will want something like this instead:
template <class T1, class T2>
Cat<T2> operator*(Dog<T1> m, Cat<T2> v)
This allows for cat and dog to have different types and be multiplied together.

To simplify it a little bit for easier "reading" and not "mixing" dogs with cats :), you can play with this overload
template <class T>
class Animal
{
private:
T size;
public:
Animal(T size1) {
size = size1;
}
T getSize() {
return size;
}
Animal<T> operator*(Animal<T> animal1)
{
T a = animal1.getSize();
T b = this->getSize();
Animal<T> animal = Animal<T>(a*b);
return animal;
}
};
int main(int argc, char* argv[])
{
Animal<double> cat(2);
Animal<double> dog(4);
Animal<double> result( dog*cat );
return 0;
}

Related

Why would I want a .* operator in C++?

I recently found out that the .* operator (and the closely related ->* operator) exists in C++. (See this question.)
Seems neat at first, but why would I ever need such a thing? The two answers in the linked question provided contrived examples which would benefit from a direct function call.
Where a direct function call is inconvenient, a function object could be used instead, like the lambda functions that may be used in std::sort. This removes a level of indirection and hence would be more performant than using .*.
The linked question also mentioned a simplified version of this example:
struct A {
int a;
int b;
};
void set_member(A& obj, int A::* ptr, int val){
obj.*ptr = val;
}
int main()
{
A obj;
set_member(obj, &A::b, 5);
set_member(obj, &A::a, 7);
// Both members of obj are now assigned
}
But it's pretty trivial (perhaps even better practice because it's cleaner and isn't unnecessarily constrained to members of A) to do this instead:
struct A {
int a;
int b;
};
void set_me(int& out, int val){
out = val;
}
int main()
{
A obj;
set_me(obj.b, 5);
set_me(obj.a, 7);
// Both members of obj are now assigned
}
In conclusion, a pointer-to-member-function might be replaced by a function object, and a pointer-to-member-variable might be replaced by a direct reference of said variable or a function object. Doing so might also increase the efficiency of the code due to one less indirection.
This question only provides examples where my conclusion stands, so it does not answer my question.
Apart from interfacing legacy code which uses .* (in which there would be no choice at all), when, really, would I want to use .*?
Your example is too trivial to be illustrative. Consider a bit more complicated one
struct A {
int a;
int b;
};
void set_n_members(A objs[], unsigned n, int A::* ptr, int val)
{
for (unsigned i = 0; i < n; ++i)
objs[i].*ptr = val;
}
int main()
{
A objs[100];
set_n_members(objs, 100, &A::b, 5);
set_n_members(objs, 100, &A::a, 7);
}
How would you rewrite this without int A::* ptr and without inducing code bloat?
You could create collections of pointers to members and iterate over them. E.g.:
struct UserStrings
{
std::string first_name;
std::string surname;
std::string preferred_name;
std::string address;
};
...
std::array<std::string UserStrings::*, 4> str_cols = { &UserStrings::first_name, &UserStrings::surname, &UserStrings::preferred_name, &UserStrings::address };
std::vector<UserStrings> users = GetUserStrings();
for (auto& user : users)
{
for (auto& column : str_cols)
{
SanitizeForSQLQuery(user.*column);
}
}
It is used to implement std::mem_fn, which is used to implement std::function.
The following code shows how the ->* operator works in a naive Function class implemention.
Similarly, you can implement a member invoker class using the .* operator and a class reference.
#include <iostream>
class A
{
public:
void greet()
{
std::cout << "Hello world"<<std::endl;
}
};
template<typename R, typename ...TArgs>
class Invoker
{
public:
virtual R apply(TArgs&& ...args) = 0;
};
template<typename C, typename R, typename ...TArgs>
class MemberInvoker :public Invoker<R, TArgs...>
{
protected:
C* sender;
R(C::*function)(TArgs ...args);
public:
MemberInvoker(C* _sender, R(C::*_function)(TArgs ...args))
:sender(_sender)
, function(_function)
{
}
virtual R apply(TArgs&& ...args) override
{
return (sender->*function)(std::forward<TArgs>(args)...);
}
};
template<typename T>
class Func
{
};
template<typename R, typename ...TArgs>
class Func<R(TArgs...)>
{
public:
Invoker<R,TArgs...>* invoker=nullptr;
template<typename C>
Func(C* sender, R(C::*function)(TArgs...))
{
invoker =new MemberInvoker<C, R, TArgs...>(sender, function);
}
R operator()(TArgs&& ...args)
{
return invoker->apply(std::forward<TArgs>(args)...);
}
~Func()
{
if (invoker)
{
delete invoker;
invoker = nullptr;
}
}
};
int main()
{
A a;
Func<void()> greetFunc(&a, &A::greet);
greetFunc();
system("PAUSE");
}
Let's say you wanted to write a LINQ style library for C++ that could be used something like this:
struct Person
{
std::string first_name;
std::string last_name;
std::string occupation;
int age;
int children;
};
std::vector<Person> people = loadPeople();
std::vector<std::string> result = from(people)
.where(&Person::last_name == "Smith")
.where(&Person::age > 30)
.select("%s %s",&Person::first_name,&Person::last_name);
for(std::string person : result) { ... };
Under the covers, the where function accepts an expression tree containing a pointer to member (among other stuff) and is applied to each vector item looking for one that matches. The select statement accepts a format string and some pointer to members and does an sprintf style formatting of whichever vector items get through the where statements.
I have written something like this, and there are several others out there that do it slightly differently (Is there a LINQ library for C++?). Pointer-to-member allows the library user to specify whichever members of their struct that they want and the library doesn't need to know anything about what they might do.

C++ Abstract Template Class

I am trying to utilize an abstract template base class.
The compiler is giving errors in RowArray.cpp that the members rowPntr, and rowSize are "not declared in this scope." Both are protected members from the abstract class AbsRow. I am guessing that this design is not possible because it utilizes virtual functions, which are dynamical bound at run time, but at the same time uses a template which is bound at compile time. Perhaps mixing the two is the issue? What I would like to know is if my design is possible, and why am I getting these compiler errors? I did also forget to mention that when creating a RowArray object RowArray<int> obj(5); I get link error 2019 in visual studio and in Qt creator it tells me undefined reverence to RowArray constructor and destructor.
Abstract class AbsRow.h
template <typename T>
class AbsRow
{
public:
virtual int getSize()const = 0;
virtual T getValue(int index)const = 0;
protected:
T *rowPntr;
int rowSize;
};
Derived Class RowArray.h
#include "absrow.h"
template <class T>
class RowArray : public AbsRow<T>
{
public:
RowArray(const int rows);
virtual ~RowArray();
virtual T getValue(int index) const override;
virtual int getSize() const override;
void setValue(int row, int value);
};
RowArray.cpp
#include "rowarray.h"
#include <cstdlib>
template <class T>
RowArray<T>::RowArray(const int rows)
{
rowSize = rows;
rowPntr = new int[rows];
for(int index = 0; index < rows; index++)
{
rowPntr[index] = (rand() % 90) + 10;
}
}
template <class T>
RowArray<T>::~RowArray()
{
delete [] rowPntr;
}
template <class T>
void RowArray<T>::setValue(int row, int value)
{
rowPntr[row] = value;
}
template <class T>
int RowArray<T>::getSize() const
{
return rowSize;
}
template <class T>
T RowArray<T>::getValue(int index) const
{
return rowPntr[index];
}
Main
#include "rowarray.h"
int main()
{
RowArray<int> row(7);
}
You can address that basically in two ways... Taking a shortened example of your RowArray.cpp ... (I also fixed a problem in your new expression)
template <class T>
RowArray<T>::RowArray(const int rows)
{
AbsRow<T>::rowSize = rows
// or
//this->rowSize = rows;
AbsRow<T>::rowPntr = new T[rows]; ///Corrected 'int' to 'T' because rowPntr is of type 'T*' in your AbsRow class
// or
//this->rowPntr = new T[rows];
for(int index = 0; index < rows; index++)
{
AbsRow<T>::rowPntr[index] = (rand() % 90) + 10;
// or
//this->rowPntr[index] = (rand() % 90) + 10;
}
}
I think error comes from the fact that you are putting template code (the derived class is still a template) into a CPP file. The compiler has to see the entire template implementation, which usually means putting the whole thing in a header file.
Another problem is that the derived class constructor assumes that rowPntr of of type int* but it is really T*.
The root cause for the problem here is, it is expected to have function definitions for template class in .h file itself. If you are not doing that compiler won't be able to link the definition from the .cpp file. There are few hacks to overcome this. One is to have an explicit template initialization in the .cpp file.
At the of RowArray.cpp add
template class AbsRow<int>;
template class RowArray<int>;

How does C++ know which attribute to use

I have the incomplete class below (but the necessary is there to understand my concern).
The following method is copying the content of a given bag (called sac in my code)
template <class T, int capInitial>
Sac<T,capInitial>& Sac<T,capInitial>::
operator+=(Sac &b) {
for(int i=0; i<b.getTaille(); i++){
*this += b.sac[i]; //LINE i DON'T UNDERSTAND
}
return *this;
}
Since the class Below has 2 attributes and a pointer to an array. In the line mentioned above what mechanism enable to take all elements in the given argument and just add it to the array of the class via *this+=b.sac[i], i would have done it in the following way
for(int i=0; i<b.getTaille(); i++){
sac[taille++]= b.sac[i];
Or perhaps there is something i don't quite understand? here is the incomplete class
template <class T, int capInitial>
class IterateurSac;
template <class T, int capInitial=64>
class Sac {
private:
T* sac;
int taille;
int capacite;
std::default_random_engine generator;
std::uniform_int_distribution<int> distribution;
void augmenterCapacite(int cap);
void copier(const Sac &b);
public:
Sac() : taille(0), capacite(capInitial), generator(7437843) {
sac= new T[capacite];
}
template <class T, int capInitial>
Sac<T,capInitial>& Sac<T,capInitial>::
operator+=(const T &element) {
if (taille==capacite)
augmenterCapacite(2*capacite);
sac[taille++]= element;
return *this;
}
}
In C++, you can create your own behaviour for operators. Your class would need to overload operator+= to make this work, and that function would name the member variable to modify.
Indeed, we can see from your first code snippet that the class is already overloading operator+= to take an argument of type Sac<T,capInitial>&; it must have another one taking an argument of type T (or compatible).
What's not clear is why the class definition you later show us does not include a declaration for either of those functions.

How to make this specialized function work

Here's the deal. I've looked on this forum and I didn't find the information I'm searching for or I'm probably not able to repeat it for my problem. I have a class Table which is generic and I have a class named MyString.
template <typename typeGen, int DIM>
class Table {
public:
TableauGenerique() : index_(0) { //On initialise courant à 0
}
void add(typeGen type);
private:
typeGen tableGen_[DIM];
int index_;
};
My problem is with the add function.
I sometimes have to do this in the main.cpp: (which works well)
Table <float,6> tabFloat;
tabFloat.add(1.6564);
and at one point, I need to do this which doesn't work because I need to specialize the add function to create an object of MyString, to pass it the string and then store the object in the array (tableGen) :
TableauGenerique <MyString,4> tabString;
So I tried this (after the class), without success.
template <typename typeGen, int DIM>
void Table<typeGen,DIM>::add(typeGen type){ //Which is the generic one for float or ints
if(index_ < DIM) {
tableGen_[courant_] = type;
index_++;
}
}
template <class typeGen, int DIM>
void Table<typeGen,DIM>::add<string>(typeGen type) { //(line 75) Which is the specific or specialized function for myString
MyString str(type);
if(index_ < DIM) {
tableGen_[courant_] = str;
index_++;
}
}
So, How can I make this work because it doesn't compile at all, saying: line75 : error: expected initializer before '<' token and in the main it says not matching function to call Table::add(const char[6]),
I hope everything is clear enough. Let me know if somethings is unclear.
Thank you very much for your help !
template <class typeGen, int DIM>
void Table<typeGen,DIM>::add<string>(typeGen type)
You're trying to specialize add() when in fact it is not a function template to begin with. How do you expect it to work?
You probably meant: (specialization of the class)
template <int DIM>
void Table<string,DIM>::add(string type)
But then this is allowed only if you specialize the class itself. Without specializing the class, the above code would give compilation error!
EDIT:
You can read these online tutorials:
Introduction to C++ Templates
14.5 — Class template specialization
Template Specialization and Partial Template Specialization
Explicit specialization (C++ only)
If you can control the code of the MyString class, you can provide constructors that act as implicit conversions from float to MyString. An example:
#include <string>
#include <sstream>
#include <iostream>
class MyString {
public:
MyString(float number) {
std::stringstream buffer;
buffer << number;
value = buffer.str();
}
void print() {
std::cout << value << std::endl;
}
private:
std::string value;
};
template <class T>
class Foo {
public:
void DoStuff(T item) {
item.print();
}
};
int main() {
Foo<MyString> foo;
foo.DoStuff(1.342); // implicitly converts float to MyString
return 0;
}
This way, you do not need any specialization of the add method. However, implicit conversions are tricky, and you have be careful not to invoke them accidentally, and they may create ambiguities.
EDIT: Upon a second thought, my suggestion below is basically equivalent to
Table<MyString,4> tabString;
tabString.add(MyString("whatever"));
and therefore excessive and/or does not solve the problem. Feel free to ignore :)
I would extend the class Table with a generic method to add something from which you can construct an object of the desired type:
template <typename typeGen, int DIM>
class Table {
public:
Table() : index_(0) {}
void add(typeGen type);
// The additional method
template<typename T> void add(const T& src);
private:
typeGen tableGen_[DIM];
int index_;
};
template<typename typeGen, int DIM>
template<typename T>
void Table<typeGen,DIM>::add(const T& src) {
if(index_ < DIM) {
tableGen_[courant_] = typeGen(src);
index_++;
}
}
Note construction of a temporary typeGen object before the assignment.
Assuming that MyString object can be constructed from a string literal, i.e. from const char*, you can then use it as following:
Table<MyString,4> tabString;
tabString.add("whatever");
or if the above assumption is wrong, the following should probably work (because you constructed a MyString instance from a string instance):
tabString.add(string("whatever"));

default template arguments in c++

Suppose i have a function template StrCompare
template<typename T=NonCaseSenCompare>//NonCaseSenCompare is a user defined class look at the detailed code below.
int StrCompare(char* str1, char* str2)
{
...
}
now in the main function i write a line
char* str1="Zia";
char* str2="zia";
int result=StrCompare(str1,str2);
it should work because we have provided a default template argument, but it does'nt compiler gives the following error
no matching function for call to `StrCompare(char*&, char*&)'
Now the detailed code is given by
#include<iostream.h>
class CaseSenCompare
{
public:
static int isEqual(char x, char y)
{
return x==y;
}
};
class NonCaseSenCompare
{
public:
static int isEqual(char x,char y)
{
char char1=toupper(x);
char char2=toupper(y);
return char1==char2;
}
};
template<typename T=NonCaseSenCompare>
int StrCompare(char* str1, char* str2)
{
for(int i=0;i < strlen(str1)&& strlen(str2);i++)
{
if(!T::isEqual(str1[i],str2[i]))
return str1[i]-str2[i];
}
return strlen(str1)-strlen(str2);
}
main()
{
char* ptr1="Zia ur Rahman";
char* ptr2="zia ur Rahman";
int result=StrCompare(ptr1,ptr2);//compiler gives error on this line
cout<<result<<endl;
system("pause");
}
If I write
int result=StrCompare<>(ptr1,ptr2);
compiler gives the same error message.
As gf and AndreyT already wrote, you can't have default template arguments with function templates. However, if you turn your comparators into function objects, you can still use default function arguments:
template<typename Comp>
int StrCompare(char* str1, char* str2, Comp = NonCaseSenCompare())
{
...
}
You can now call StrCompare() like this
StrCompare("abc","aBc",CaseSenCompare());
or like this:
StrCompare("abc","aBc"); // uses NonCaseSenCompare
A comparator would then have to look like this:
struct CaseSenCompare {
bool operator()(char x, char y) const {return x==y;}
};
Adjust StrCompare() accordingly.
§14.1/9:
A default template-argument shall not
be specified in a function template
declaration or a function template
definition, nor in the
template-parameter-list of the
definition of a member of a class
template.
A simple work-around would be to move it into a class:
template<typename T=NonCaseSenCompare>
struct StrCompare {
static int compare(char* str1, char* str2) { /* ... */ }
};
Firstly, function templates do not support default template arguments, only class templates do.
Secondly, even when all class template parameters have default arguments, you still have to specify an empty <> to refer to that class template.
What i use is next trick;
lets say you want to have function like this
template <typename E, typename ARR_E = MyArray_t<E> > void doStuff(ARR_E array)
{
E one(1);
array.add( one );
}
you will not be allowed, but i do next way:
template <typename E, typename ARR_E = MyArray_t<E> >
class worker {
public:
/*static - as you wish */ ARR_E* parr_;
void doStuff(); /* do not make this one static also, MSVC complains */
};
template <typename E, typename ARR_E>
void worker::doStuff<E, ARR_E>::getChunks()
{
E one(1);
parr_->add( one );
}
so this way you may use it like this.
MyArray_t my_array;
worker<int> w;
w.parr_ = &arr;
w.doStuff();
as we can see no need to explicitly set second parameter.
maybe it will be useful for someone.