I am working on a project that uses templated objects as a vector argument. I must strictly use objects and any primitive types. I'm working on a smaller example to help me grasp the bigger picture.
So far, here is what I have:
#include <iostream>
#include <vector>
using namespace std;
template <class T>
class Thing {
public:
Thing(T type) {
memVar = type;
}
T getMemVar() {
return memVar;
}
private:
T memVar;
};
class U {
public:
U(int i) {
j = i;
}
int getJ () {
return j;
}
private:
int j;
};
int main() {
// your code goes here
vector < Thing <U> > v;
v.push_back(); // idk how to add new elements to this vector.
// I've tried: v.push_back(Thing <U> i(U)),
// v.push_back(U obj(4)), etc etc...
return 0;
}
I don't know how to add elements to this vector.
By example
v.push_back(Thing<U>(4));
If you can compile C++11 or newer, even simpler
v.emplace_back(4)
But, in both cases, you have to modify the constructor of Thing as follows
Thing(T type) : memVar(type) {
}
or add a default constructor in U
U () {
}
because your Thing constructor try to initialize memVar without arguments and next to copy type in memVar
Related
I have a class like this:
class MyClass {
MyClass(double *v, int size_of_v){
/*do something with v*/
};
};
My question: Is there any way, I can initialize such class without defining an array of double and feeding it to the constructor?
I would like to do something like:
auto x = MyClass({1.,2.,3.}, 3);
It is called list initialization and you need a std::initilizer_list constructor, that to be achieved in your MyClass.
#include <initializer_list>
class MyClass
{
double *_v;
std::size_t _size;
public:
MyClass(std::initializer_list<double> list)
:_v(nullptr), _size(list.size())
{
_v = new double[_size];
std::size_t index = 0;
for (const double element : list)
{
_v[index++] = element;
}
};
~MyClass() { delete _v; } // never forget, what you created using `new`
};
int main()
{
auto x = MyClass({ 1.,2.,3. }); // now you can
//or
MyClass x2{ 1.,2.,3. };
//or
MyClass x3 = { 1.,2.,3. };
}
Also note that providing size_of_v in a constructor is redundant, as it can be acquired from std::initializer_list::size method.
And to completeness, follow rule of three/five/zero.
As an alternative, if you can use std::vector, this could be done in a much simpler way, in which no manual memory management would be required. Moreover, you can achieve the goal by less code and, no more redundant _size member.
#include <vector>
#include <initializer_list>
class MyClass {
std::vector<double> _v;
public:
MyClass(std::initializer_list<double> vec): _v(vec) {};
};
Well you can use std::vector instead the double*v & it would fit perfectly for your goal
class MyClass {
MyClass(vector<double> v){
/*do something with v*/
};
};
As we know in c++, we can reinitialize an array arr of size N with a value 0 as,
fill (arr, arr + N, 0);
But I need to reinitialize the array with a struct S,
struct S {
int b[2];
}
The actual code is,
#include <iostream>
using namespace std;
struct Dog
{
int count[2];
};
int main(){
...
Dog dogs[N];
...
while (T--)
{
...
for (int i = 0; i < M; ++i)
{
fill(dogs, dogs+N, {0});
...
}
...
}
}
For the case:
struct Dog { int count[2]; };
Dog dogs[N];
you can use:
std::fill(dogs, dogs+N, Dog{});
The third argument to fill must have the right type already, the compiler does not deduce the type from the iterator. So you cannot just use {} or {0}.
Consider using std::begin(dogs), std::end(dogs) instead of dogs, dog+N as that removes the possibility of using the wrong value for N.
I'm not sure why fill was designed this way, as it is certainly possible to write a function which does accept initializer list as well as normal values:
#include <algorithm>
template<typename It>
void mfill(It begin, It end, typename std::remove_reference<decltype(*begin)>::type const &v)
{
std::fill(begin, end, v);
}
struct Dog { int count[2]; };
int main()
{
Dog dogs[5];
mfill(dogs, dogs+5, {});
}
You can use fill_n as follows:
struct Dog
{
int count[2];
};
int main(){
Dog dogs[4] = {};
dogs[0].count[0] = 1;
std::fill_n(dogs, 0, Dog{});
}
Since Dog is a pod structure, you can default construct it in the last parameter of fill_n
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
I have some generic code for deleting pointers within a vector or a value of a Map.
Is there a better way of doing this (without using shared_ptrs or any o fthe tr1 extensions )?
Also is the code correct?
Here is my code:
I have a namespace
#ifndef CONTAINERDELETE_H
#define CONTAINERDELETE_H
#include <functional>
#include <map>
#include <vector>
#include <algorithm>
namspace ContainerDelete{
template<class A, class B>
struct DeleteMap
{
bool operator()( pair<A,B> &x) const
{
delete x.second;
return true;
}
};
template<class T>
struct DeleteVector
{
bool operator()(T &x) const
{
delete x;
return true;
}
};
}
#endif
I would then use this namespace in some bit of code to delete a map or vector.
Test Map deletion.
#include "ContainerDelete.h"
using namespace std;
// Test function.
void TestMapDeletion()
{
// Add 10 string to map.
map<int,B*> testMap;
for( int Idx = 0; Idx < 10; ++Idx )
{
testMap[Idx] = new B();
}
// Now delete the map in a single line.
for_each( testMap.begin(),
testMap.end(),
ContainerDelete::DeleteMap<int,B*>());
}
Test Vector Deletion
// Test Function.
void TestVectorDeletion()
{
// Add 10 string to vector.
vector<B*> testVector;
for( int Index = 0; Index < 10; ++Index )
{
testVector.push_back( new B());
}
// Now delete the vector in a single line.
for_each( testVector.begin(),
testVector.end(),
ContainerDelete::DeleteVector<B*>());
}
Thanks,
Mike
Better would be if reduce the genericity as:
struct DeleteVector
{
template<class T> //use the template here!
void operator()(T &x) const
{
delete x;
}
};
if you do so, then you could simply write this:
for_each(testVector.begin(),
testVector.end(),
ContainerDelete::DeleteVector());
No need to pass type argument when you use DeleteVector, for it is not a class template anymore!
Similarly, you can implement DeleteMap functor.
You should also rename DeleteVector to DeleteT, and DeleteMap to DeletePairSecond, as both of these can be used more generically. For example, DeleteT can be used even with std::list, or even with arrays.
The code is ok. I can't imagine any other ways to delete the pointers. All you can do is to reduce explicit type specification like in upper question. I know one more uglier way to do it: functions deduce types of their template parameters. So you can write template function with the first argument - vector, second - ptr and then use std::bind of vector parameter to make this function accepting one parameter - ptr.
But functor is better and more flexible.
I'm trying to write a fake vector for my class assignment, and I currently get an error in the member function pushBack.
The compiler doesn't seem to like incrementing the SIZE variable which holds the number of elements in the "vector". Is there something I might need to fix?
Your assistance would be highly appreciated for helping me with this, and any other problems you might happen to find.
/*
Write a simple program that simulates the behavior of vectors
-You should be able to add and remove elements to the vector
-You should be able to access an element directly.
-The vector should be able to hold any data type.
*/
#include <stdio.h>
template <class T, int SIZE>
class Vector
{
#pragma region constructors&destructors
private:
T vec[SIZE];
public:
Vector()
{}
~Vector()
{}
#pragma endregion
template <class T/*, int SIZE*/>
void defineVec(T var)
{
for(int i=0; i<SIZE; i++)
{
vec[i] = var;
}
//printf("All elements of the vector have been defined with %", var)
//What should I do when trying to print a data type or variable
//of an unspecified one along with the '%'?
}
template <class T/*, int SIZE*/>
void pushBack(T var)
{
SIZE ++; //C1205
vec[SIZE - 1] = var;
}
template <class T/*, int SIZE*/>
void popBack()
{
vec[SIZE - 1] = NULL;
SIZE--;
}
//template <class T/*, int SIZE*/>
void showElements()
{
for(int i=0; i<SIZE; i++)
{
printf("%d",vec[i]);
printf("\n");
}
}
};
int main()
{
Vector <int, 5> myints;
myints.pushBack(6);
myints.showElements();
return 0;
}
You're passing SIZE as a template parameter. Inside the definition of a template, a non-type template parameter is basically a constant -- i.e., you can't modify it.
You'll need to define a separate variable to keep track of how much of the storage in your vector-alike is currently being used.