This is a simple question, and I am sure that it has been answered before but I cannot seem to find a good answer.
I have a class, Point:
template<class T>
Point{
\\code
}
...and now I want a vector of Points, some of which have T as an integer which have T as a double. I want to write something like
template<class T>
std::vector<Point<T> > points;
But, alas, this doesn't compile with the error "expected primary-expression before 'template'". I haven't been able to fidget with this code to make it work. Also relevant is that points is in the main class, so I can't stick the template declaration outside the function.
If someone could direct me to a solution, I would be much obliged.
Thanks.
If your goal is to have a vector that holds both Point<int> and Point<double> you can use Boost Variant.
typedef boost::variant<Point<int>, Point<double> > VariantPoint;
Then:
std::vector<VariantPoint> my_vector;
my_vector.push_back(Point<int>(1, 0));
my_vector.push_back(Point<double>(1.5f, 2.0f));
Will work. Note that to inspect the elements afterwards, you probably will have to use the visitor pattern as documented here.
If your goal is to have distinct vector types that can only hold one type of Point, then you may use:
template<typename T> using PointVector = std::vector<Point<T>>; // C++11
// Now you can write:
PointVector<int> my_vector;
// Which is equivalent to:
std::vector<Point<int>> my_vector;
Or, if C++11 is not an option:
template<typename T> struct PointVector
{
typedef std::vector<Point<T> > Type;
}
Then:
PointVector<int>::Type my_vector;
To get a single kind of vector, I would use inheritance:
template <typename T>
struct PointVector : public std::vector< Point<T> >
{
};
Note, the inheritance is just a mechanism to achieve the equivalent of a template typedef. This means, PointVector should not contain any data members or virtual functions. However, #ereOn's suggestion is preferred, and is discussed in the answer to this question.
The old fashioned way to achieve a variant would be to use a union.
class IntOrDouble {
union {
int i;
double d;
};
bool is_int;
bool is_double;
public:
IntOrDouble () : is_int(false), is_double(false) {}
IntOrDouble (int x) : is_int(true), is_double(false) { i = x; }
IntOrDouble (double x) : is_int(false), is_double(true) { d = x; }
int operator = (int x) {
is_int = true;
is_double = false;
return i = x;
};
double operator = (double x) {
is_int = false;
is_double = true;
return d = x;
};
operator int () const {
if (is_int) return i;
if (is_double) return d;
return 0;
}
operator double () const {
if (is_double) return d;
if (is_int) return i;
return 0;
}
};
typedef std::vector< Point<IntOrDouble> > PointVector;
But it all seems a little over the top for this use case. I'd just use vectors of double all around, unless memory was really tight.
Related
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.
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.
I'm not an advanced programmer. How can I overload the [] operator for a class that has two (or more) array/vector type variables?
class X
{
protected:
std::vector<double> m_x, m_y;
public:
double& operator[](const short &i) { return ???; }
};
What should I use for ???, or how can I do it (maybe adding other definitions?) to be able to call either variable?
Additional question: will this allow other classes of type class derived : public X access m_x and m_y for writing?
UPDATE:
Thank you everyone who answered, but I'm afraid that if I draw the line then the answer to my first question is no, and to the second yes. The longer version implies either an extra struct, or class, or plain setters/getters, which I wanted to avoid by using a simple function for all.
As it stands, the current solution is a (temporary) reference to each variable, in each class to avoid the extra X:: typing (and keep code clear), since m_x would have existed, one way or another.
you can write just a function for this, like:
double &get(unsigned int whichVector, unsigned int index)
{
return (whichVector == 0 ? m_x[index] : m_y[index]);
}
or use operator():
struct A
{
std::vector<int> a1;
std::vector<int> a2;
int operator()(int vec, int index)
{
return (vec == 0 ? a1[index] : a2[index]);
}
};
A a;
auto var = a(0, 1);
but still, this is kinda strange :) probably you should just give a const ref outside, like:
const std::vector<double> &getX() const { return m_x; }
and second question: protected will be convert into private in public inheritance (child/derived will have access to these memebers)
Assuming you want m_x and m_y indexed against the same parameter and a single return value:
struct XGetter
{
double& x;
double& y;
};
XGetter operator[](const short &i) { return { m_x[i], m_y[i] }; }
And the const overload:
struct XGetterReadOnly
{
double x;
double y;
};
XGetterReadOnly operator[](const short &i) const { return { m_x[i], m_y[i] }; }
The compiler will make a good job of optimizing away the intermediate classes XGetter and XGetterReadOnly where appropriate which maybe hard to get your head round if you're a new to C++.
If using mixin doesn't make you uncomfortable you could use tag dispatching like:
#include <utility>
#include <vector>
#include <iostream>
template <size_t I>
struct IndexedVector {
std::vector<double> v;
IndexedVector():v(10){}
};
template <size_t I>
struct tag {
int i;
};
template <size_t S, class = std::make_index_sequence<S>>
struct MixinVector;
template <size_t S, size_t... Is>
struct MixinVector<S, std::index_sequence<Is...>>: IndexedVector<Is>... {
template <size_t I>
double &operator[](tag<I> i) {
return IndexedVector<I>::v[i.i];
}
};
int main() {
MixinVector<2> mv;
mv[tag<0>{0}] = 1.0;
std::cout << mv[tag<0>{0}] << std::endl;
}
To use std::index_sequence you need however compiler supporting c++14 (you could though implement it yourself in c++11). The approach is easily expandable to any number of vectors by simple MixinVector template parameter modification.
There are many broken things, either at conceptual and design level.
Are you able to point your finger simultaneously against two distinct things? No? That's why you cannot use one index to address two distinct vector retaining their distinction.
You can do many things: whatever way to "combine" two value int one is good
by a syntactic point of view:
return m_x[i]+m_y[x] or return sin(m_x[i])*cos(m_y[i]) or return whatever_complicated_expression_you_like_much
But what's the meaning of that? The point is WHY THERE ARE TWO VECTOR IN YOUR CLASS? What do you want them to represent? What do you mean (semantically) indexing them both?
Something I can do to keep their distinction is
auto operator[](int i) const
{ return std::make_pair(m_x[i],m_y[i]); }
so that you get a std::pair<double,double> whose fist and second members are m_x[i] and m_y[i] respectively.
Or ... you can return std::vector<double>{m_x[i],m_y[i]};
About your other question: Yes, inheriting as public makes the new class able to access the protected parts: that's what protected is for.
And yes, you cam R/W: public,protected and private are about visibility, not readability and writeability. That's what const is about.
But again: what does your class represent? without such information we cannot establish what make sense and what not.
Ok, stated your comment:
you need two different funcntions: one for read (double operator[](unsigned) const) and one for write (double& operator[](unsigned) const)
If you know vectors have a known length -say 200-, that you can code an idex transforamtion like i/1000 to identify the vector and i%1000 to get the index,so that 0..199 addres the first, 1000..1199 address the second 2000..2199 address the third... etc.
Or ... you can use an std::pair<unsigned,unsigend> as the index (like operator[](const std::pair<unsigned,unsigned>& i), using i.first to identify the vector, and i.second to index into it, and then call x[{1,10}], x[{3,30}] etc.
Or ... you can chain vetor together as
if(i<m_x.size()) return m_x[i]; i-=m_x:size();
if(i<m_y.size()) return m_y[i]; i-=m_y:size();
if(i<m_z.size()) return m_z[i]; i-=m_z:size();
...
so that you index them contiguously.
But you can get more algorithmic solution using an array of vectors instead of distinct vector variables
if you have std::array<std::vector<double>,N> m; instead of m_x, m_y and m_z the above code can be...
for(auto& v: m)
{
if(i<v.size()) return v[i];
i-=v.size();
}
You can return a struct has two double
struct A{
double& x;
double& y;
A(A& r) : x(r.x), y(r.y){}
A(double& x, double& y) : x(x), y(y){}
};
class X
{
protected:
std::vector<double> m_x, m_y;
public:
A operator[](const short &i) {
A result(m_x[i], m_y[i]);
return result;
}
};
Thank for editing to #marcinj
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 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>;
}