Template classes and initializing an array to zero - c++

I posted earlier today about template classes, but was pretty far off and got a solution to my previous problem from here. Of course when that's dealt with, there's always a new one that I can't seem to figure out.
Given the following constructor:
template <typename Type, int inSize>
sortedVector<Type, inSize>::sortedVector():
size(inSize), vector(new Type[inSize]), amountElements(0)
{}
I want to make a dynamic array, which I then can insert elements of whatever type into via an add-method. The calls from main will look as follows:
sortedVector<Polygon, 10> polygons;
sortedVector<int, 6> ints;
How can I initialize the array to zero when it's constructed? I can not set an object to zero ;)
I thought I was being smart and tried to overload the =-operator for Polygon and given an int it would do nothing. Turns out I can not do that ):
Any good suggestions?
Also, here's the template class sortedVector:
template <typename Type, int inSize>
class sortedVector
{
public:
sortedVector();
int getSize();
int getAmountElements()
bool add(const Type &element);
private:
Type *vector;
int size;
int amountElements;
};
and just in case also Polygon:
class Polygon
{
public:
Polygon();
Polygon(Vertex inVertArr[], int inAmountVertices);
~Polygon();
void add(Vertex newVer);
double area();
int minx();
int maxx();
int miny();
int maxy();
int getAmountVertices() const;
friend bool operator > (const Polygon &operand1, const Polygon &operand2);
friend bool operator < (const Polygon &operand1, const Polygon &operand2);
private:
Vertex *Poly;
int amountVertices;
};

Initialize the array elements to Type(). This is what the standard library containers do. For built-in numeric types, Type() is equivalent to 0. For class/struct types, Type() constructs a temporary default-constructed object.

You can just use Type() to get a default constructed object. A better approach is to use std::vector<T> either directly or via a thin wrapper adding whatever functionality or constraints are needed. Although it is doable without std::vector<T> any solution which actually properly manages resources and objects will end up reimplementing at least parts of std::vector<T>.

Just assign every element of the "vector" (confusing name, by the way, given the prominence of std::vector<>) to the default value. The default value is just Type(), so you'd do something like this in the constructor body:
std::fill(vector, vector + size, Type());

How can I initialize the array to zero when it's constructed? I can
not set an object to zero ;)
You can use so-called default constructed value. In other words, you need to define (if it is not defined) special value that will play role of zero for your object.

Related

C++ how to initialize/copy const array member from array parameter in constructor

The following class is meant to store a single bool and an array of 100 integers. I want a constructor that takes as parameters a single bool and a 100-element array (which are then copied into the object). The obvious way to write this is the following
class Info {
private:
const int contents[100];
const bool symmetric;
public:
Info (const int contents[100], bool symmetric) : contents(contents), symmetric(symmetric) {}
// ...
};
But unfortunately this does not compile, the contents argument in the member initialiser list (the third contentson that line) seems to be regarded as a pointer.
Can I get this to work or is this a C++ limitation?
I do not want to use std::array or std::vector for space and efficiency reasons. [edited] Mine is a C++ syntax question and not about whether std::array is efficient or not. The answer may be useful in related situations that do not allow the use of std::array. [end edited]
Initializing in the constructor body does not work, because contents is const.
I am using C++14 with clang (CLion in linux) and come from the Java world.
There is also another way other than std::array, but you should use templates and use variadic parameter feature.
Lets assume that the number of elements is amount then first declare your class like :
#include <utility>
template<size_t amount, typename = std::make_index_sequence<amount> >
class Info;
then define your class as the following:
template<size_t amount, size_t ... _Idx>
class Info<amount, std::integer_sequence<size_t, _Idx...> > {
private:
const int contents[amount];
const bool symmetric;
public:
Info (const int contents_[amount], bool symmetric_) : contents{contents_[_Idx]...}, symmetric(symmetric_) {}
};
now you use your class for any amount without any problem:
const int preinfo[3] = {1,2,3};
Info<3> minfo(preinfo, true);
This method will make it very fast but please note that nothing is free and using this code will make your code to produce a bigger binary after compilation!

Designing a literal-type class with a variant field inside in which one or three objects may be stored

I'm trying to design a class - let's call it A for the sake of discussion - that will fulfill a specific set of requirements:
A must be a literal type to allow the compiler to initialize its global instances at compile time via constexpr constructors (many global const objects of this type are created in the source code). The reason for this is that A employs simple compile-time encryption (mostly XOR) on the integers. Decryption is later done at runtime while accessing the appropriate int.
Its central private field is a simple integer. However, the class has two constructors:
A::A(int x) and A::A(int x, int y, int z). If the first version is invoked, then later, at runtime, that single x will be used by the class internally whenever a method call that needs to use it is made. In contrast, if the second version with three parameters is used, it will be decided at runtime which one of x, y and z to use if a function that needs one is invoked.
A must be a single type; one type for the first constructor and another type for the second constructor is not satisfactory (A is frequently passed to functions as an argument, so without this constraint, I would need to duplicate or templatize all those functions).
A great majority of all A objects will be global constants, assignment will seldom happens, and if it does, it will certainly not be between an object with three ints and an object with one int or vice-versa.
To summarize: A will be instantiated as global const objects. If I initialize an object with a single int, that single int should be stored inside it (and nothing more). If I initialize it with three ints, then those three ints should be stored inside. There's no need to worry about assignment from a three-int object to a one-int object or vice versa, because they're all constants.
The solutions I have considered so far are as follows:
Make A a template; the template parameter would be what I called the StorageType. That storage would abstract access to that central int resource by exposing an accessor for it. The problem of choosing which int field to use would then be moved from the A to this helper storage type. The idea is roughly illustrated by this code:
template<typename StorageType>
class A
{
private:
StorageType storage;
public:
constexpr A(int x, int y, int z) :
storage(x, y, z)
{ }
constexpr A(int x) :
storage(x)
{ }
void doSomething()
{
auto theRightInt = storage.getInt();
// ...
}
};
Problem: violates constraint 3.
As before, but rather than templatize A on the StorageType, have a generic interface that describes the StorageType and store a unique_ptr to one inside A.
Problem: violates constraint 1.
Store the integers as a union:
union
{
struct
{
int x;
int y;
int z;
} intPack;
int singleInt;
};
In this variant, each A object - including those that only use a single int - has room for three possible ints. Another option would be to use boost::variant instead of the obsolete union.
Problem: This is wasteful - see point 4. If boost::variant is used, it violates constraint 1 since boost::variant, unlike std::variant from C++17, is not a literal type.
Rather than attempt to represent the "variance" of the central integer field inside A, do it externally: have the class always store a single int, and create a helper class - let's call it VariantA - that contains three versions of A, each initialized with what was x, y and z in the constructor mentioned in point 2. VariantA would have an accessor function that decides at runtime which A object to return.
Problem: Tedious to use because the accessor has to be invoked every single time:
VariantA a1(0, 1, 2);
VariantA a2(10, 20, 30);
auto a3 = a1.get() + a2.get();
someFunctionThatTakesAnA(a1.get());
// etc
Question:
Is there an elegant solution to this problem that I have missed, or will I have to choose one of the solutions I have considered (and rejected) above?
My platform is VC++, so use of C++11/4 is okay except some more esoteric parts, but the features from C++17 drafts are not yet available.
Seems like the best thing you could use is a conditionally sized range of ints:
class A {
std::array<int, 3> data;
bool one;
public:
constexpr A(int x): data{{x, 0, 0}}, one(true) { }
constexpr A(int x, int y, int z): data{{x, y, z}}, one(false) { }
constexpr size_t size() const { return one ? 1 : 3; }
constexpr const int* begin() const { return data.data(); }
constexpr const int* end() const { return data.data() + size(); }
};
I'm not entirely sure what your logic is for selecting which element, but if you have a 1-sized range, you get that element, if you have a 3-sized range, then you do whatever it is you need to do.
Regardless of the specific details, the main point is that you want a type that has 3 ints and a bool. You need to store 3 ints, you want it to be literal, and you want it to know whether it's storing 3 or 1 int. That pretty much spells out the type. The only thing left is to determine how you want the data access to look, and that's not specified.
A class/struct with 2 members?
A pointer to int and a bool (where the boolean say if the pointer point to one or three values)?
#include <iostream>
struct foo
{
bool single;
int const * p;
constexpr foo ( int const & x ) : single{true}, p{&x}
{}
constexpr foo ( int const * y ) : single{false}, p{y}
{}
};
constexpr int x{2};
constexpr int y[]{3, 5, 7};
int main ()
{
constexpr foo f1{x};
constexpr foo f3{y};
}

c++ sort class with class vector inside

I have a class cl1:
class c1
{
long double * coords;
...
}
I also have a second class cl2:
class cl2
{
vector<cl1*> cl1_vec;
unsigned int d;
...
}
I would like to sort cl1_vec, from cl2, based on coords[d], using the sort function for vectors.
So i could have something like
sort(cl2_inst->cl1_vec.begin(),cl2_inst->cl1_vec.end(), ??? );
I tried approches like
sort the 'std::vector' containing classes
C++ std::sort with predicate function in Class
but i couldn't make my way to solving this.
Thanks for any help that comes this way.
The code i've tried:
class cl1 {
public:
long double* coords;
cl1(long double *, unsigned int);
cl1();
cl1(const cl1& orig);
virtual ~cl1();
};
class cl2 {
public:
unsigned int d;
vector<cl1*> cl1_vec;
//the srting functions
static bool compareMyDataPredicate(cl1* lhs, cl1* rhs)
{
return (lhs->coords[d] < rhs->coords[d]);
};
// declare the functor nested within MyData.
struct compareMyDataFunctor : public binary_function<my_point*, my_point*, bool>
{
bool operator()( cl1* lhs, cl1* rhs)
{
return (lhs->coords[d] < rhs->coords[d]);
}
};
...
...
}
then in main
std::sort(cl2_inst->cl1_vec.begin(),cl2_inst->cl1_vec.end(),cl2::compareMyDataPredicate() );
The error is because you are accessing a non-static member d from a static context of the comparator function. Use the second approach, in the following way:
Provide a constructor to that struct, which takes a parameter unsigned int and sets a member to that value.
Create an object of type compareMyDataFunctor, and pass in the value of d to the constructor.
Use this object for sorting (3rd argument to std::sort)
I am not sure about the problems, because you were not precise enough about what exactly "does not work" means in your case (does not compile, does compile but does not sort etc). In case it does not compile (most likely guess) you did not post the error messages, which also makes finding and explaining the problem very hard.
Here are some guesses based on the code you posted:
Both static function as well as the functor use the member d to decide which column to sort on. However d is an instance variable, so it is not available for anything which is static. Neither the functor nor the static member function would know which of the possible ds to use, as there is one d per instance.
The best way to do this without resorting to C++11 features (lamdas) is to provide a constructor to the functor which takes the d you are planning to use. Something like this:
struct compareMyDataFunctor : public binary_function<cl1*, cl1*, bool>
{
compareMyDataFunctor( unsigned int d ) : d( d ) {}
bool operator()( cl1* lhs, cl1* rhs)
{
return (lhs->coords[d] < rhs->coords[d]);
}
unsigned int d;
};
This should do the trick.
There are some more things wrong with the code you posted though:
Arrays should be indexed using type size_t not a unsigned int. Same goes for std::vectors
The types in the std::binary_function instantiation do not match the actual types in the method (may be a problem of reducing the code).
Do not use using namespace std (I assume you do from the declarations in your code).
Functors such as these should take parameters as const-reference, not by value.
That's all I can think of. Next time try to present short, self contained, complete examples, then people will not have to resort to guessing.

C++ Construction Behaviour

class OSwitch {
private:
Operator *operators[];
//int variable; <-- unused variable
public:
OSwitch() {}
~OSwitch() {}
void setOperator(int id, Operator *op) {
operators[id] = op;
}
void execute(int id) {
operators[id]->execute();
}
};
There are several subclasses of the abstract baseclass Operator.
When calling setOperator() for more than one time, the array "forgets" the last element.
for example
XOperator a;
YOperator b;
os.setOperator(1,a);
os.setOperator(2,b);
os.execute(1); // <- wont work
But when the int variable (or any other variable in OperatorSwitch) is declared, it works.
I dont have any idea how this works.
Thanks for any hint.
Your member variable operators is an unsized array, which is an incomplete type and not allowed in a class definition.
What you probably want instead is a map of integers to pointers:
#include <map>
class OSwitch
{
private:
std::map<int, Operator *> operators;
public:
void setOperator(int id, Operator *op) { operators[id] = op; }
void execute(int id) { operators[id]->execute(); }
};
Note that it will be an error to call execute on an ID that has not been assigned a valid pointer. You can make this more robust by checking for existence of the map element first.
Array operators doesn't have a size declared. Either declare the number of elements in the array, as in operators[10], or use std::vector instead.
You need to initialize the array before adding data.
I would recommend you to work with values, not pointers, in this array, because then you won't have problems defining who will delete the Operator*s afterwards (i.e. the caller of setOperator or ~OSwitch()).

Variable amount of function arguments in C++

So, in C the standard way is stdarg.h. But I'm looking to pull up something a bit like this:
template<int A>
class MyClass {
public:
MyClass(...) {
// fill each value of array with an argument.
};
virtual ~MyClass() { };
private:
float array[A];
};
Obviously, the idea is not to have different constructions for every possible amount of arguments. Any suggestions, standard ways, whatsoever?
Thanks,
Julian.
In C++11 you can use an std::initializer_list constructor for this kind of scenario. That allows for this type of initialization:
MyClass<5> x{1,2,3,4,5};
although you have to define what happens when the dimensions do not match. But for these kinds of statically sized arrays, it is worth looking at std::array. These have a well defined behaviour when the dimensions of the initializer don't match their own.
you need to use initializer_list
explicit MyClass(std::initializer_list<T> list_args){
// fill each value of array with an argument.
};
If you don't have access to C++11 initializer_lists you can just pass a vector.
MyClass(const std::vector& values) {
//copy values into array
};
MyClass someClass( std::vector<int>(10,4) ); //adds 10x 4 to the vector