Initializing struct via member initialization list - c++

So I'm learning C++ from Stephen Prata book and I want to do one exercise... So the problem is this:
I want to use a std::valarray inside a struct, inside a class like this:
class Wine
{
private:
struct Pair
{
std::valarray<int> valYear;
std::valarray<int> valBottlesNum;
};
int m_yearNum;
Pair m_numericData;
public:
Wine();
Wine(int, const int[], const int[]);
};
And initialize this via member initialization list:
Wine::Wine(int yearNum, const int year[], const int bottlesNum[])
: m_yearNum(yearNum),
m_numericData.valYear(yearNum, year),
m_numericData.valBottlesNum(yearNum, bottlesNum)
{}
But it just doesn't want to work. Somehow compiler does not like this "." to access members of a m_numericData struct in a initializer list.
I could just abandon Pair struct and do valYear and valBottlesNum as a simple class member variables and initilize them like this...
Wine::Wine(, int yearNum, const int year[], const int bottlesNum[])
: m_yearNum(yearNum), m_valYear(yearNum, year), m_valBottlesNum(yearNum, bottlesNum)
{}
but I really want to know how to solve this kinda stuff.
Thanks in adavnce!

You can move the individual initialisations into the body of the constructor:
Wine::Wine(int yearNum, const int year[], const int bottlesNum[])
: m_yearNum(yearNum)
{
m_numericData.valYear = std::valarray<int>(yearNum, year);
m_numericData.valBottlesNum = std::valarray<int>(yearNum, bottlesNum);
}
Alternatively, give Pair its own constructor.

The valarray constructor you're attempting to use takes a T const* to the data and an std::size_t argument indicating the number of array elements that the first argument points to. If you can use C++11, then change yearNum to std::size_t and you can use list-initialization, which in turn will aggregate initialize the Pair.
Wine::Wine(std::size_t yearNum, const int year[], const int bottlesNum[])
: m_yearNum(yearNum)
, m_numericData{{year, yearNum}, {bottlesNum, yearNum}}
{}
Live demo

Related

Is it possible to make a C++ function for a data type that is accessible using a dot operator?

I want to make a function associated to a data type say int that can be accessed using the dot operator such that:
int x = 9;
std::string s = x.ToString();
I know how to do so with std::string and the likes but not the int data type. Is that possible?
No, this is not possible. An int is a primitive type whereas a std::string is a class type that contains methods.
However, you could create your own struct/class in order to implement this functionality. The struct Int type has a constructor which takes in an integer and uses an initializer list :a(value) to assign the internal integer with a given value.
#include <string>
struct Int
{
int a;
Int(int value)
: a(value)
{}
std::string ToString() const { return std::to_string(a); }
};
int main()
{
Int a = 20;
std::string s = a.ToString();
}

Inheritance and array of types

I have a probably very simple question in C++.
Let's say I have class defined as:
class PS
{
private:
int value;
int m;
public:
PS();
PS(int value, int m);
PS(int m);
};
Now I want to define an array with elements of this type. For example,
PS t[3];
However, I want all of the elements in this array to have m=2. How would I do that? I am assuming I have to use inheritance some how, right?
So for example I don't want to do something like this:
>PS t[3];
>t[0].PS(2);
>t[1].PS(2);
>t[2].PS(2);
I want to do it one show for all elements of t.
Using your constructor, you can simply use brace initialization :
PS t[] = { PS(2) , PS(2), PS(2) };
Or as suggested by #0x499602D2, since PS has a non explicit constructor, simply :
PS t[] = { 2, 2, 2 };
I would also suggest you to use std::array<> instead of C-style arrays.
It is not really safe not to initialize a value but you can use the C++11 feature that allows you to initialize variable directly in your class definition :
class PS {
private:
int value;
int m = 2;
public:
PS() {};
};
If you are using an older version of C++ you can consider overloading the default constructor
class PS {
private:
int value;
int m;
public:
PS(int _m = 2) : m(_m) {};
};
The STL Vector class is preferred to c-arrays. Using one, you could do:
std::vector<PS> t(3, PS(2));

Syntax on Constructors with Const Members [duplicate]

This question already has answers here:
How to initialize a const field in constructor?
(6 answers)
How to initialize const member variable in a class?
(11 answers)
Closed 9 years ago.
I haven't done C++ coding in some time, and my friend is having trouble with his homework. I never really worked with const, and it's making this a nightmare as I can't figure out the correct syntax for the constructor. Imagine I have this in dvd.h:
class DVD {
const string title;
int minutes;
double price;
public:
DVD(const string t, int m, double p);
}
3 private member variables, the string is const. The constructor also takes a const string.
So now, in dvd.cpp I can do the following:
#include "dvd.h"
DVD::DVD(const string t, int m, double p) {
const string title = t;
minutes = m;
price = p;
}
And all is well in the world. However, when I modify minutes in dvd.h to be const (which is how his professor structured the file), we have this in dvd.h:
class DVD {
const string title;
const int minutes; // Here is the change
double price;
public:
DVD(const string t, int m, double p);
}
So, now that minutes is const, I get the following compilation errors:
assignment of read-only member 'DVD::minutes' dvd.cpp
uninitialized member 'DVD::minutes' with 'const' type 'const int' [-fpermissive] dvd.cpp
Which I suppose makes sense, because I'm trying to set a value into a const variable. So then I tried doing the same thing as with the const string title in dvd.cpp in order to resolve the error:
DVD::DVD(const string t, int m, double p) {
const string title = t;
const int minutes = m; // Was 'minutes = m;'
price = p;
}
and got the following (1) errors and (1) warnings:
uninitialized member 'DVD::minutes' with 'const' type 'const int' [-fpermissive] dvd.cpp
unused variable 'minutes' [-Wunused-variable] dvd.cpp
So I guess I'm struggling to figure out what the darn syntax is for this... title and minutes are supposed to be const, but the constructor's parameter list for DVD takes only a const string. I can't figure out what I'm missing - it's been a while since I last coded in C++.
const string title = t;
That declares a local variable. All is not well with the world: you haven't set the member variable to the value you want. To initialise members, use the constructor's initialiser list:
DVD::DVD(const string t, int m, double p) :
title(t), minutes(m), price(p)
{}
Your version tries to default-initialise each member (since they aren't mentioned in the initialiser list), then assign each of them. This doesn't work for members which can't be default-initialised (such as references, or class types without a default constructor) or assigned to (such as const members).
You can initialize your const and non-const members simply like this:
DVD::DVD(const string t, int m, double p)
: title(t)
, minutes(m)
, price(p)
{}
Note that, if you are using C++98/03, you may want to pass the string parameter as const& (to avoid useless and inefficient calls to string copy constructor):
DVD(const string& t, ...other stuff...)
... same init as above
If you are using C++11 (which implements move semantics), you can pass the string parameter by value, and std::move() from the value:
DVD::DVD(string t, int m, double p)
: title(std::move(t)),
, minutes(m)
, price(p)
{}

How can I create an array of class objects whose constructor require few arguments?

I've read about solution const A a[3] = { {0,0}, {1,1}, {2,2} }, but in my program const can't be used:
class Paper: public PaperQueue{
...
protected:
typedef int (Utils::*funcPtr) (int, int); //I use external function there
funcPtr p;
Utils* fptr;
public:
int pricefunc(){
addprice = (fptr->*p) (t,price);
}
Paper(int n, unsigned int pr):PaperQueue(n){
...
p=&Utils::commonpricefunc;
}
void Put(int a){
...
}
...
}
class Bank{
...
void Buy(Paper &p){
(/*this function modifies many parameters in 'p'*/)
...
}
...
}
int main(){
Bank B;
int pn=5;
/* ? */ const Paper p[pn] = {{5,15},{5,15},{5,15},{5,15},{5,15}}; /* ? */
int paperloop=0;
...
p[paperloop].Put(p[paperloop].addprice);
B.Buy(p[paperloop]);
...
That gives me a LOT of errors(with pricefunc(),Put(),Buy(),...), or just "variable-sized object ā€˜pā€™ may not be initialized". Is there any way to make this array work? (Everything works fine if not to pass any parameters to constructor!)
You can't use initializer lists for classes (non-PODs) because that would bypass the call to the constructor. You'll have to change it to a POD or use std::vector in the following ways:
If the class is copyable, as it appears to be, you can create a std::vector and fill it with the values you want:
const vector<Paper> papers(5, Paper(5, 15));
If you want to initialize it with different values, you can use an initializer list, but this is only supported in C++11:
const vector<Paper> papers = {Paper(1, 1), Paper(2, 2)};
Without C++11, you'll have to add the elements one by one, but then you can't make the vector const:
vector<Paper> papers;
papers.push_back(Paper(1, 1));
papers.push_back(Paper(2, 2));
Please check the code below, it can be compiled:
class Paper {
public:
int x, y;
};
int main() {
Paper p[5] = {{5,15}, {5,15}, {5,15}, {5,15}, {5,15}};
}
Please refer this post for more details, I think it explains very well

How do I declare a constant pair inside my header file

#include <utility>
class C {
private:
const std::pair<int,int> corner1(1,1);
};
GCC reports error: expected identifier before numeric constant.
I need to construct the object on the moment of it's declaration since it's const, but I can't seem it get the right syntax.
I need to construct the object on the moment of it's declaration since it's const, but I can't seem it get the right syntax.
No, you can only initialize non-integral types - const or not (at least pre-C++11) in the constructor initializer list:
class C {
private:
const std::pair<int,int> corner1;
C() : corner1(1,1) {}
};
But it seems to me like you don't need to replicate the member in every instance, so I'd just make it static instead:
class C {
private:
static const std::pair<int,int> corner1;
};
//implementation file:
const std::pair<int,int> C::corner1(1,1);
If you pass -std=c++11 and you are using a more recent version of gcc, you can do this:
class C {
private:
const std::pair<int,int> corner1{1,1}; // Note curly braces
};