Variable amount of function arguments in C++ - 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

Related

How do I make a dynamic constructor which takes in x amount of parameters, in c++?

How do I make a dynamic constructor which takes in x amount of parameters, in c++?
For example:
my_constructor(int,int,...);
there can be as many ints as the user inputs.
Is this even possible?
If they're all arguments of the same type, simply use an initializer list.
struct foo
{
foo(std::initializer_list<int> init)
{
....
}
}
You'd still need to add these to a container of some kind, however (for example):
struct foo
{
std::vector<int> v;
foo(std::initializer_list<int> init)
: v(init.begin(), init.end())
{ }
};
The way you're talking about it, I don't think it would be possible. How would you assign all those arguments to fields? You'd need to dynamically generate different fields for the object! I'm almost certain that's not possible. What you can do instead, however, is make the constructor take an array as part of its arguments, which you can fill with a varying number of 'sub-arguments'.
Good luck.

How do I instantiate an array's size later?

Let's say I have a base class called
Class Base {
public:
std::string array[];
};
The size the string array is not decided until another class extends it, what's the correct syntax for doing so?
EG, later on in a derived class
Derived::Derived() {
array[] = new array[40];
}
If you want to use a C-style array, the size must be fixed and known at compile-time. And even in that case, you could use the safer, zero-overhead std::array<> wrapper instead.
If the size of your container is not known at compile-time, then it is good practice to use std::vector (or std::deque in some cases, based on your requirements in terms of memory allocation) and avoid manual memory management through raw pointers, new[] and delete[]:
#include <string> // For std::string
#include <vector> // For std::vector
class Base {
public:
std::vector<std::string> myVector;
};
Besides, this design won't require any dedicated work in the constructor (and destructor) of Derived. If all that was done by Derived's default constructor was to allocate the array, now you can avoid explicitly defining a default constructor at all, and let the compiler generate one for you implicitly - same story for the destructor.
Also, I would discourage you from using names of standard container classes (like array) as names for your variables. Something like myArray (or myVector, as in my example above) are more appropriate choices.
You don't. Arrays in C++ are of compile-time fixed size. You cannot just resize them to your liking.
The bad way to do this using only language features is to actually have your member as an std::string*:
std::string* array;
And then dynamically allocate an array of std::strings, assigning the pointer to the first element to array:
Derived::Derived() {
array = new std::string[40];
}
The good way to do this is to use library features. The standard library provides container types for you to use. Try a std::vector<std::string>:
std::vector<std::string> array;
Which you could initialise to contain 40 strings like so:
Derived::Derived()
: array(40)
{ }
Why not use a std::vector<std::string> so that you don't have to worry about size. The container resizes automagically as new things are inserted into it.
Using a vector of string is normally better solution.
But this will work:
Class Base {
Public:
std::string *array;
};
Derived::Derived() {
array = new array[40];
}
I'd add:
Class Base {
Public:
std::string *arr;
Base():arr(nullptr){}
Base(sizr_t s):arr(new std::string[s]){}
~Base(){delete []arr;}
};
Derived::Derived():Base(40) { }
And you may need to write copy/move constructors and asignments. Derived dont have to know about very much.
Now compare with:
Class Base {
Public:
std::vector<std::string> arr;
Base(){}
Base(sizr_t s):arr(s){}
};
All other special functions: destructor, copy/move constructors and asignments are generated by compiler. And the constructor of Derived is still:
Derived::Derived():Base(40) { }
Also... you may want to make arr private or at least protected?
The correct syntax is
std::vector<std::string> array;
As well as the done-to-death heap allocation, you can size it statically as in:
template <int N>
class Base
{
public:
std::string array[N];
};
class Derived : Base<40>
{ ... }
Pros: simple, avoids (relatively slow) memory allocation at runtime and the hassles of cleanup (smart array pointer or otherwise). Cons: each instantiation of Base is a distinct type, which can lead to a little more bloat and less interoperability.

How to add an Initializer List constructor to STL vector

So what I want to do is extend the existing vector class in my program to allow me to say this,
vector<string>* vec = new vector<string>(){"Value1","Value2"};
or
vector<string>* vec = new vector<string>({"Value1","Value2"});
or
vector<string> vec = {"Value1","Value2"};
I know I can accomplish something like this but doing this,
string temp[] = {"Value1","Value2"};
vector<string> vec(temp, temp+ sizeof(temp) / sizeof( temp[0] ) );
This uses the vectors iterator constructor but can't I remove the extra line?
I know in C# you can add whatever you want to existing things by using the partial key word like this,
public partial class ClassName
{
ClassName(Stuff stuff)
{
}
void AmazingNewMethod()
{
}
}
Does C++ have a nifty trick like this somewhere?
Do I have to inherit vector and build a customVector that has a constructor that behind the scenes does the iterator constructor thing?
Maybe wrap those lines in a static Helper Function call that sets it by Reference and add it to a toolbox class somewhere?
I feel like lots of programmers have hit this problem. Are there any elegant solutions out there?
Thanks.
Edit: fixed the title to mention this is an Initializer List constructor.
In C++11 there would be initializer lists to suite this approach. As you're mentioning .NET I now assume that you're using MS Visual Studio. Microsoft does NOT implement initializer lists, therefore the easiest way to accomplish something like that would be a function that returns the vector with all the elements added.
On the partial thing: C++ does not offer a feature in the same vein as .NET's partial classes.
The C++ 2011 way is to accept an std::initializer_list<T> as a constructor argument:
#include <initializer_list>
template <typename T>
class foo {
T *d_array;
public:
foo(std::initializer_list<T> list)
: d_array(new T[list.size()]) {
std::copy(list.begin(), list.end(), this->d_array);
}
foo(foo const&);
foo& operator= (foo const&);
~foo() { delete[] this->d_array; }
};
The above clearly only concentrates on how use an std::initializer_list<T>. To actually do the allocation internally you'd allocate raw memory and construct the object in-place. However, this wasn't what the question is about.
With respect to adding this support to std::vector<T>: you don't have to! In C++ 2011 std::vector<T> can be initialized with an std::initializer_list<T>. In C++ 2003 you can't do this. The best you could do is to support construction from an array, using a constructor looking something like this:
template <typename T>
template <typename S, int Size>
foo<T>::foo(S const (&array)[Size])
d_array(new T[Size]) {
std::copy(array, array + Size, d_array);
};
However, there is no way to extend an existing without changing its type. To avoid reimplementing most of the members you could publically inherit from the type you want to extend and add all required constructors (these are not inherited; in C++ 2011 you could inherit the existing constructors but then, with C++ 2011 you wouldn't need to do any of this anyway).
An alternative you might want to use with C++ 2003 is to create a factor function taking a built-in array, i.e. something like this:
template <typename T, typename S, int Size>
std::vector<T>
make_vector(S const (&array)[Size]) {
return std::vector<T>(array, array + Size);
}
char const* init[] = { "Hello", "World" };
std::vector<std::string> value = make_vector<std::string>(init);

Template classes and initializing an array to zero

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.

Declare and initialise an array of struct/class at the same time

1.
I know that it is possible to initialise an array of structures in the declaration. For example:
struct BusStruct
{
string registration_number;
string route;
};
struct BusStruct BusDepot[] =
{
{ "ED3280", "70" },
{ "ED3536", "73" },
{ "FP6583", "74A" },
};
If the structure is changed into a class, like this:
class BusClass
{
protected:
string m_registration_number;
string m_route;
public:
// maybe some public functions to help initialisation
};
Is it possible to do the same as for the structure (i.e. declare and initialise an array of classes at the same time)?
2.
Am I correct to think that it is not possible to declare and initialise vector<BusStruct> or vector<BusClass> at the same time?
Is it possible to do the same as for the structure (i.e. declare and initialise an array of classes at the same time)?
Not unless you create a suitable constructor:
class BusClass
{
protected:
string m_registration_number;
string m_route;
public:
// maybe some public functions to help initialisation
// Indeed:
BusClass(string const& registration_number,
string const& route)
:m_registration_number(registration_number),
m_route(route) { }
};
Or you make all members public and omit the constructor, in which case you can use the same initialization syntax as for the struct. But i think that's not what you intended.
Am I correct to think that it is not possible to declare and initialise vector<BusStruct> or vector<BusClass> at the same time?
No it's not possible with current C++. You can however use libraries that make this possible. I recommend Boost.Assign for that. For that, however, your class has to have a constructor, and likewise your struct too - Or you need to create some kind of factory function
BusStruct make_bus(string const& registration_number,
string const& route) { ... }
If you want to keep the struct initializable with the brace enclosed initializer list in other cases.
No, you would not be able to initialize classes the way you can with structures. But you can write the class constructor inside the array declaration.
C++ has no built in way of initializing vectors, unless you want to load the vector from an array that you have initialized.
C++ natively supports two forms of vector initialization and neither is what you are looking for.
1: Every element the same as in:
vector<int> ints(4,1000); //creates a vector of 4 ints, each value is 1000.
2: Copy from an existing vector as in:
vector<int> original(3,1000); //original vector has 3 values, all equal 1000.
vector<int> otherVector(original.begin(),original.end()); //otherVector has 3 values, copied from original vector