Passing function to template object when initializing template in C++ - c++

I'm trying to write an implementation for hash map, I'm not allowed to use anything from stdlib except for iostream, string and cassert.
It needs to be generic, so the values that populate the buckets can be of any type. I need templates for this, but can't manage to pass the hash function in any way. This would be the header file:
template<typename Value, typename hashFunction>
class hashTable{
public:
hashTable(int size){
//Creates an empty vector of size on the table
}
define(Value v){
loads value in Vector[hashFunction(v)];
}
...
private:
Vector with all the elements
}
Note: I guess I don't need templates for the keys, do I?
I can't define the hash function inside my class because I'd have to make one that works with all types (string to int, int to int, double to int, etc). So I guess the only solution is to pass the function as argument in my main. This would be the main.
int hashF(int v){return v}
int main(){
hashTable<int,int,hashF> table(5);
}
But this doesn't work, g++ tells me "expected type but got hashF". I guess I could pass a pointer to a function, but that seems like a hack rather than a real solution. Is there a better way?

template<typename Value, int(*fun)(Value)>
class hashTable {
std::vector<Value> v;
public:
hashTable(std::size_t size) : v(size) { }
void define(Value &&val) { v[fun(val)] = val; }
};
Live Demo
Non function pointer way:
template<typename Value, typename F>
class hashTable {
std::vector<Value> v;
F fun;
public:
hashTable(std::size_t size, F fun_) : v(size), fun(fun_) { }
void define(Value &&val) { v[fun(val)] = val; }
};
Live Demo

Managed to get it working with Neil's advice. My hash.h:
template<typename C, typename D, typename H>
class Tabla {
public:
Tabla(int s){
cout << hashF(3) << endl;
size=s;
}
private:
H hashF;
int size;
};
My hash.cpp
struct KeyHash {
unsigned long operator()(const int& k) const
{
return k % 10;
}
};
int main(){
Tabla<int,int,KeyHash> tab(3);
return 0;
}
This example is just to show I'm able to use the function inside the template, then I'd have to code the define and delete functions that use that KeyHash.
Dunno why I have to wrap it like this, but it works. Found the specifics of it here

Related

How do I call template array operator overloading function?

I need to create an adapter C++ class, which accepts an integer index, and retrieves some types of data from a C module by the index, and then returns it to the C++ module.
The data retrieving functions in the C module are like:
int getInt(int index);
double getDouble(int index);
const char* getString(int index);
// ...and etc.
I want to implement an array-like interface for the C++ module, so I created the following class:
class Arguments {
public:
template<typename T> T operator[] (int index);
};
template<> int Arguments::operator[] (int index) { return getInt(index); }
template<> double Arguments::operator[] (int index) { return getdouble(index); }
template<> std::string Arguments::operator[] (int index) { return getString(index); }
(Template class doesn't help in this case, but only template member functions)
The adapter class is no biggie, but calling the Arguments::operator[] is a problem!
I found out that I can only call it in this way:
Arguments a;
int i = a.operator[]<int>(0); // OK
double d = a.operator[]<double>(1); // OK
int x = a[0]; // doesn't compile! it doesn't deduce.
But it looks like a joke, doesn't it?
If this is the case, I would rather create normal member functions, like template<T> T get(int index).
So here comes the question: if I create array-operator-overloading function T operator[]() and its specializations, is it possible to call it like accessing an array?
Thank you!
The simple answer is: No, not possible. You cannot overload a function based on its return type. See here for a similar quesiton: overload operator[] on return type
However, there is a trick that lets you deduce a type from the lhs of an assignment:
#include <iostream>
#include <type_traits>
struct container;
struct helper {
container& c;
size_t index;
template <typename T> operator T();
};
struct container {
helper operator[](size_t i){
return {*this,i};
}
template <typename T>
T get_value(size_t i){
if constexpr (std::is_same_v<T,int>) {
return 42;
} else {
return 0.42;
}
}
};
template <typename T>
helper::operator T(){
return c.get_value<T>(index);
}
int main() {
container c;
int x = c[0];
std::cout << x << "\n";
double y = c[1];
std::cout << y ;
}
Output is:
42
0.42
The line int x = c[0]; goes via container::get_value<int> where the int is deduced from the type of x. Similarly double y = c[1]; uses container::get_value<double> because y is double.
The price you pay is lots of boilerplate and using auto like this
auto x = c[1];
will get you a helper, not the desired value which might be a bit unexpected.

Virtually turn vector of struct into vector of struct members

I have a function that takes a vector-like input. To simplify things, let's use this print_in_order function:
#include <iostream>
#include <vector>
template <typename vectorlike>
void print_in_order(std::vector<int> const & order,
vectorlike const & printme) {
for (int i : order)
std::cout << printme[i] << std::endl;
}
int main() {
std::vector<int> printme = {100, 200, 300};
std::vector<int> order = {2,0,1};
print_in_order(order, printme);
}
Now I have a vector<Elem> and want to print a single integer member, Elem.a, for each Elem in the vector. I could do this by creating a new vector<int> (copying a for all Elems) and pass this to the print function - however, I feel like there must be a way to pass a "virtual" vector that, when operator[] is used on it, returns this only the member a. Note that I don't want to change the print_in_order function to access the member, it should remain general.
Is this possible, maybe with a lambda expression?
Full code below.
#include <iostream>
#include <vector>
struct Elem {
int a,b;
Elem(int a, int b) : a(a),b(b) {}
};
template <typename vectorlike>
void print_in_order(std::vector<int> const & order,
vectorlike const & printme) {
for (int i : order)
std::cout << printme[i] << std::endl;
}
int main() {
std::vector<Elem> printme = {Elem(1,100), Elem(2,200), Elem(3,300)};
std::vector<int> order = {2,0,1};
// how to do this?
virtual_vector X(printme) // behaves like a std::vector<Elem.a>
print_in_order(order, X);
}
It's not really possible to directly do what you want. Instead you might want to take a hint from the standard algorithm library, for example std::for_each where you take an extra argument that is a function-like object that you call for each element. Then you could easily pass a lambda function that prints only the wanted element.
Perhaps something like
template<typename vectorlike, typename functionlike>
void print_in_order(std::vector<int> const & order,
vectorlike const & printme,
functionlike func) {
for (int i : order)
func(printme[i]);
}
Then call it like
print_in_order(order, printme, [](Elem const& elem) {
std::cout << elem.a;
});
Since C++ have function overloading you can still keep the old print_in_order function for plain vectors.
Using member pointers you can implement a proxy type that will allow you view a container of objects by substituting each object by one of it's members (see pointer to data member) or by one of it's getters (see pointer to member function). The first solution addresses only data members, the second accounts for both.
The container will necessarily need to know which container to use and which member to map, which will be provided at construction. The type of a pointer to member depends on the type of that member so it will have to be considered as an additional template argument.
template<class Container, class MemberPtr>
class virtual_vector
{
public:
virtual_vector(const Container & p_container, MemberPtr p_member_ptr) :
m_container(&p_container),
m_member(p_member_ptr)
{}
private:
const Container * m_container;
MemberPtr m_member;
};
Next, implement the operator[] operator, since you mentioned that it's how you wanted to access your elements. The syntax for dereferencing a member pointer can be surprising at first.
template<class Container, class MemberPtr>
class virtual_vector
{
public:
virtual_vector(const Container & p_container, MemberPtr p_member_ptr) :
m_container(&p_container),
m_member(p_member_ptr)
{}
// Dispatch to the right get method
auto operator[](const size_t p_index) const
{
return (*m_container)[p_index].*m_member;
}
private:
const Container * m_container;
MemberPtr m_member;
};
To use this implementation, you would write something like this :
int main() {
std::vector<Elem> printme = { Elem(1,100), Elem(2,200), Elem(3,300) };
std::vector<int> order = { 2,0,1 };
virtual_vector<decltype(printme), decltype(&Elem::a)> X(printme, &Elem::a);
print_in_order(order, X);
}
This is a bit cumbersome since there is no template argument deduction happening. So lets add a free function to deduce the template arguments.
template<class Container, class MemberPtr>
virtual_vector<Container, MemberPtr>
make_virtual_vector(const Container & p_container, MemberPtr p_member_ptr)
{
return{ p_container, p_member_ptr };
}
The usage becomes :
int main() {
std::vector<Elem> printme = { Elem(1,100), Elem(2,200), Elem(3,300) };
std::vector<int> order = { 2,0,1 };
auto X = make_virtual_vector(printme, &Elem::a);
print_in_order(order, X);
}
If you want to support member functions, it's a little bit more complicated. First, the syntax to dereference a data member pointer is slightly different from calling a function member pointer. You have to implement two versions of the operator[] and enable the correct one based on the member pointer type. Luckily the standard provides std::enable_if and std::is_member_function_pointer (both in the <type_trait> header) which allow us to do just that. The member function pointer requires you to specify the arguments to pass to the function (non in this case) and an extra set of parentheses around the expression that would evaluate to the function to call (everything before the list of arguments).
template<class Container, class MemberPtr>
class virtual_vector
{
public:
virtual_vector(const Container & p_container, MemberPtr p_member_ptr) :
m_container(&p_container),
m_member(p_member_ptr)
{}
// For mapping to a method
template<class T = MemberPtr>
auto operator[](std::enable_if_t<std::is_member_function_pointer<T>::value == true, const size_t> p_index) const
{
return ((*m_container)[p_index].*m_member)();
}
// For mapping to a member
template<class T = MemberPtr>
auto operator[](std::enable_if_t<std::is_member_function_pointer<T>::value == false, const size_t> p_index) const
{
return (*m_container)[p_index].*m_member;
}
private:
const Container * m_container;
MemberPtr m_member;
};
To test this, I've added a getter to the Elem class, for illustrative purposes.
struct Elem {
int a, b;
int foo() const { return a; }
Elem(int a, int b) : a(a), b(b) {}
};
And here is how it would be used :
int main() {
std::vector<Elem> printme = { Elem(1,100), Elem(2,200), Elem(3,300) };
std::vector<int> order = { 2,0,1 };
{ // print member
auto X = make_virtual_vector(printme, &Elem::a);
print_in_order(order, X);
}
{ // print method
auto X = make_virtual_vector(printme, &Elem::foo);
print_in_order(order, X);
}
}
You've got a choice of two data structures
struct Employee
{
std::string name;
double salary;
long payrollid;
};
std::vector<Employee> employees;
Or alternatively
struct Employees
{
std::vector<std::string> names;
std::vector<double> salaries;
std::vector<long> payrollids;
};
C++ is designed with the first option as the default. Other languages such as Javascript tend to encourage the second option.
If you want to find mean salary, option 2 is more convenient. If you want to sort the employees by salary, option 1 is easier to work with.
However you can use lamdas to partially interconvert between the two. The lambda is a trivial little function which takes an Employee and returns a salary for him - so effectively providing a flat vector of doubles we can take the mean of - or takes an index and an Employees and returns an employee, doing a little bit of trivial data reformatting.
template<class F>
struct index_fake_t{
F f;
decltype(auto) operator[](std::size_t i)const{
return f(i);
}
};
template<class F>
index_fake_t<F> index_fake( F f ){
return{std::move(f)};
}
template<class F>
auto reindexer(F f){
return [f=std::move(f)](auto&& v)mutable{
return index_fake([f=std::move(f),&v](auto i)->decltype(auto){
return v[f(i)];
});
};
}
template<class F>
auto indexer_mapper(F f){
return [f=std::move(f)](auto&& v)mutable{
return index_fake([f=std::move(f),&v](auto i)->decltype(auto){
return f(v[i]);
});
};
}
Now, print in order can be rewritten as:
template <typename vectorlike>
void print(vectorlike const & printme) {
for (auto&& x:printme)
std::cout << x << std::endl;
}
template <typename vectorlike>
void print_in_order(std::vector<int> const& reorder, vectorlike const & printme) {
print(reindexer([&](auto i){return reorder[i];})(printme));
}
and printing .a as:
print_in_order( reorder, indexer_mapper([](auto&&x){return x.a;})(printme) );
there may be some typos.

How do you create a template definition for a fixed-size array class in C++?

I need to create a template because I don't know what it's an array of. And it needs to be of the size that's passed in the constructor. So here is what I got and I got all sorts of errors. I am a beginner to C++ so any help is appreciated :)
template <typename T, int N>
class Array
{
public:
T& operator[](int index)
{
return data[index];
}
private:
int size;
T *data[N];
};
I think you understand what I'm trying to do. I also need to overload the subscript operator, as you can see. Not sure if I need a reference or a pointer or what. I did have a constructor but it wasn't working properly.
Here's a corrected version with a sample main as well:
#include <iostream>
using namespace std;
template <typename T, int N>
class Array
{
public:
T& operator[](int index)
{
// add check for array index out of bounds i.e. access within 0 to N-1
return data[index];
}
Array() {
data = new T[size = N];
}
~Array() {
if (data)
delete [] data;
}
private:
int size;
T *data;
};
int main(void) {
Array<int, 4> a;
a[0] = 5;
cout << a[0] << endl;
return 0;
}
From what I can see your template is containing an array of pointers, which from what I read and from your [] operator implementation is not what you intend to do. So first you should remove the * from :
T *data[N];
You should probably initialize the size of your template from your constructor, thus you should change :
T *data[N];
to :
T* data;
and :
template <typename T, int N>
to :
template<typename T>
Now that changes the implementation a bit, you should now write a constructor like that :
template<typename T>
Array(int n) {
data = new T[n];
}
and now you should also add a destructor like that :
~Array() {
delete[] data;
}
and there you go :)
However if you want to keep the size as an argument of the template your constructor go like :
template<typename T, int N>
Array() {
}
and the declaration of data :
T data[N];
As said in comments, you may want to use std::array in "real life" conditions, but as a training, implementing your own Array is a good thing to do, that's a training most computer schools do after all.

templated variable

I currently have the following non templated code:
class Vector{
public:
double data[3];
};
static Vector *myVariable;
void func() {
myVariable->data[0] = 0.;
}
int main() {
myVariable = new Vector();
func();
}
I then want to template the dimension :
template<int DIM> class Vector{
public:
double data[DIM];
};
static Vector<3>* myVariable;
void func() {
myVariable->data[0] = 0.;
}
int main() {
myVariable = new Vector<3>();
func();
}
But I finally want to template my variable as well, with the dimension :
template<int DIM> class Vector{
public:
double data[DIM];
};
template<int DIM> static Vector<DIM> *myVariable;
void func() {
myVariable->data[0] = 0.;
// or perform any other operation on myVariable
}
int main() {
int dim = 3;
if (dim==3)
myVariable = new Vector<3>();
else
myVariable = new Vector<4>();
func();
}
However, this last version of the code produces an error : this static variable cannot be templated ("C2998: Vector *myVariable cannot be a template definition").
How could I possibly correct this error without a complete redesign (like inheriting the templated Vector class from a non templated class, which would require more expensive calls to virtual methods , or manually creating several myVariables of different dimensions) ? Maybe I'm just tired and don't see an obvious answer :s
Edit: Note that this code is a minimal working code to show the error, but my actual implementation templates the dimension for a full computational geometry class, so I cannot just replace Vector by an array. I see that there doesn't seem to be a solution to my problem.
Thanks!
It's been a while, but I've used constants in the template declaration before. I eventually went another direction with what I was working on, so I don't know if it'll ultimately be your solution either. I think the problem here is that any templated variable must know its template argument at compile time.
In your example, Vector<3> and Vector<4> are different types, and cannot be assigned to the same variable. That's why template<int DIM> static Vector<DIM> *myVariable doesn't make any sense; it doesn't have a discernible type.
template<int DIM> static Vector<DIM> *myVariable;
This is not allowed by the language specification. End of the story.
And since I don't understand the purpose of your code, or what you want to achieve, I cannot suggest any better alternative than simply suggesting you to try using std::vector<T>. It's also because I don't know how much am I allowed to redesign your code, and the way you use it, to make your code work.
You can use std::array to template-ize the dimension but you can't cast the pointer of one dimension to the pointer of another.
I think I found!
template<int DIM> class Vector{
public:
double data[DIM];
};
static void *myVariable;
template<int DIM>
void func() {
((Vector<DIM>*)myVariable)->data[0] = 0.;
// or perform any other operation on myVariable
}
int main() {
int dim = 3;
if (dim==3)
{
myVariable = (void*) new Vector<3>();
func<3>();
}
else
{
myVariable = (void*) new Vector<4>();
func<4>();
}
}
Vector<3> and Vector<4> are entirely different types and have no formal relation to one another. The fact that they are superficially similar from your point of view doesn't matter.
If you want them to be equivalent up to a certain type, we have a name for that: interfaces
template <typename Scalar = float>
class BasicVector {
public:
typedef Scalar * iterator;
virtual ~ BasicVector () {}
virtual size_t size () const = 0;
virtual iterator begin () = 0;
virtual iterator end () = 0;
};
template <unsigned N, typename Scalar = float>
class Vector : public BasicVector <Scalar> {
Scalar m_elements [N];
public:
using Scalar :: iterator;
size_t size () const {return N;}
iterator begin () {return m_elements;}
iterator end () {return m_elements + N;}
};
int main () {
BasicVector * a;
a = new Vector <3>;
a = new Vector <4>;
}

How to deduce array size from an enum template argument?

How should I change the code below so that Array<Index> array; is enough and the SIZE is automatically deduced from the enum?
Even if the enum changes, it is guaranteed that it contains SIZE referring to the correct size.
template <typename Enum, int N>
class Array {
public:
int& operator[](Enum index) { return array[index]; }
private:
int array[N];
};
enum Index { X, Y, SIZE };
int main() {
Array<Index, SIZE> array;
array[X] = 1;
return 0;
}
UPDATE: As for "Array<type> means you're creating an array of Type objects" (Jerry) and "the name of class template is a bit misleading" (Nawaz): actually I am creating CustomSqlQueryModel<TableColumns>. The above is just a simplified code, nothing more. Jerry and Nawaz are rigth: this simplified code is unfortunate.
You can write a traits class. This requires a bit of extra work each time you define a new enum type, but no extra work for each occurrence of Array<Index> in user code:
template<class Enum>
struct ArrayTraits;
template<class Enum>
struct Array {
int& operator[](Enum index) { return array[index]; }
private:
int array[ArrayTraits<Enum>::size];
};
enum Index { X, Y, SIZE };
template<>
struct ArrayTraits<Index> {
enum { size = SIZE };
};
int main() {
Array<Index> array;
array[X] = 1;
return 0;
}
One of the advantages of this is you can specialize the traits for external enums you don't control, as long as you know how to get the max size.
As stated, I don't think you can. If, however, you change it to something like:
struct Index {
enum { X, Y, SIZE};
};
Then your template could be something like:
template <class Enum>
class Array {
// ...
private:
int array[Enum::SIZE];
};
...and if the type you pass as Enum doesn't include some positive constant named SIZE,the instantiation won't compile. For the purpose at hand, you'd really kind of prefer that Index was a namespace, but since a namespace isn't a type, I don't think you can use it as a template argument.
I should add, however, that I'm not sure I like this idea at all -- most people are going to think Array<type> means you're creating an array of Type objects, and this is clearly something entirely different from that...
If you want only the size to be template argument, not the type , as from your example it seems that the type of the array would be always int, then why don't you implement this:
template <int size>
class Array {
public:
int& operator[](int index) { return array[index]; }
//Note this addition!
int operator[](int index) const { return array[index]; }
private:
int array[size];
};
int main() {
Array<10> array;
array[0] = 1;
array[1] = 2;
return 0;
}
Note this addition: it's better if you implement const version of operator[] too, so that const Array<> can use it to access the array elements, otherwise your class wouldn't work for const Array<>.