Error when initialazing struct member array - c++

I have this struct:
template<int N>
struct XYarr
{
double x[N],y[N];
int size() {return N;}
};
When I try to intialize it (and return it by a function)
return XYarr<size>{x2, y2}; //x2 and y2 are arrays double[size]
I get the following error: cannot initialize an array element of type 'double' with an lvalue of type 'double [200]'. What is the problem?

Raw arrays don't have value semantics. Thus they can't be initialized or assigned using the = operator and need to be copied explicitly. For example, using a constructor like this:
#include <algorithm>
template<int N>
struct XYarr
{
double x[N], y[N];
XYarr(const double(&x2)[N], const double(&y2)[N]) {
std::copy(std::begin(x2), std::end(x2), x);
std::copy(std::begin(y2), std::end(y2), y);
}
int size() const { return N; }
};
int main() {
double x2[4]{}, y2[4]{};
XYarr<4> test{ x2, y2 };
}

Compiler can't use member aggregate initialization because C-arrays can't be copied.
To overcome this, provide a constructor for your struct:
template<int N>
struct XYarr
{
XYarr() = default; // default constructor if needed
XYarr(const double (&x_)[N], const double (&y_)[N]) {
memcpy(&x,x_,sizeof (double)*N);
memcpy(&y,y_,sizeof (double)*N);
}
double x[N],y[N];
int size() {return N;}
};
int main(int argc, char * argv[]) {
XYarr<100> a; // default constructor
double x2[100], y2[100];
auto n = XYarr<100>{x2, y2}; // init constructor
return 0;
}
There is an std::array version for comparison. std::array can be used with member aggregate initialization - so no boilerplate code, everything is simple.
template<int N>
struct XYarr_stl
{
std::array<double,N> x,y;
int size() {return N;}
};
int main(int argc, char * argv[]) {
std::array<double,100> x2_stl, y2_stl;
auto n_stl = XYarr_stl<100>{x2_stl, y2_stl};
// this will give compilation error, because array sizes will be checked at compile time
//std::array<double,200> x2_stl2, y2_stl2;
//auto n_stl2 = XYarr_stl2<100>{x2_stl2, y2_stl2};
return 0;
}

Related

How to validate input parameters in C++ constructor?

Following example shows the crux of the problem. I need to initialize const members of a class. This can only be done in the initializer-list and not in constructor body. I want to assert or throw an error if input to the constructor is invalid, that is, if the vector size is less than 3.
class A {
// In following constructor, how do we make sure if params.size()
// is at least 3.
A(const std::vector<int>& params):
x(params[0]), y(params[1]), z(params[2]) {}
private:
const int x;
const int y;
const int z;
};
Please advise how to achieve this in Modern C++ (11 and later)
Just add a layer of abstraction. You can write a function that makes sure the vector is of the correct size and you can even make sure the values are in an expected range, if you have one. That would look like
class A {
A(const std::vector<int>& params):
x(verify(params, 0)), y(verify(params, 1)), z(verify(params, 3)) {}
private:
static int verify(const std::vector<int>& params, int index)
{
if (params.size() < 4) // or use if (params.size() <= index) if you only care if the index will work
throw something;
return params[index];
}
const int x;
const int y;
const int z;
};
const members can only be initialized in the constructors's member initialization list. To validate the caller's input, you would have to call a helper function to validate each input value before passing it to the corresponding member, eg:
int check(const std::vector<int> &params, int index) {
if (params.size() <= index) throw std::length_error("");
return params[index];
}
class A {
A(const std::vector<int>& params):
x(check(params, 0)), y(check(params, 1)), z(check(params, 3)) {}
private:
const int x;
const int y;
const int z;
};
Or, simply utilize the vector's own built-in bounds checking instead:
class A {
A(const std::vector<int>& params):
x(params.at(0)), y(params.at(1)), z(params.at(3)) {}
private:
const int x;
const int y;
const int z;
};
Not as elegant as other solutions but... you can simply add a throw in a ternary operator inside the initialization of the first constant
class A
{
private:
const int x;
const int y;
const int z;
public:
A (const std::vector<int>& params)
: x{ params.size() < 4u ? throw std::runtime_error{"!"}
: params[0] },
y{params[1]}, z{params[3]}
{ }
};
Off Topic suggestion: if A is a class, maybe it's better that the constructor is public.
Other option extra layer through conversion:
class A_params{
friend class A;
int x;
int y;
int z;
void validate();
public:
A_params(std::initializer_list<int>);
A_params(const std::vector<int>&);
A_params(int(&)[3]);
//...
};
class A {
// In following constructor, how do we make sure if params.size()
// is at least 3.
public:
A(A_params params):
x(params.x), y(params.y), z(params.z) {}
private:
const int x;
const int y;
const int z;
};

Autodetect return type of template function

I have a some classes with a function. In all classes the function has the same name and argument type but different return type. I need a some template function which can automagically detect correct template substitution without angle brackets.
Test code to illustrate question:
struct Float
{
static Float convert(int i)
{
return Float{static_cast<float>(i)};
}
float _f;
};
struct Int
{
static Int convert(int i)
{
return Int{i};
}
int _i;
};
template<typename T>
T convert(int i)
{
return T::convert(i);
}
int main()
{
Float f1 = convert<Float>(10);
Int i1 = convert<Int>(10);
// Float f2 = convert(10); compilation error
// Int i2 = convert(10); compilation error
return 0;
}
P.S. templates makes me crazy I want but can't understand them.
Not sure if it's a perfect fit to your needs, but you may simulate what you want with a class and a templated conversion operator:
class convert {
int arg;
public:
convert(int arg) : arg(arg) {}
template<class T>
operator T() const {
return T::convert(arg);
}
};
Since template argument deduction works for templated conversion operators, you can write this:
Float f1 = convert(10);
Int i1 = convert(10);
Just like you want.
Why do you need the convert function? You can use a single argument constructor to do the same job.
struct Float
{
Float(int i)
{
_f = static_cast<float>(i);
}
float _f;
};
struct Int
{
Int(int i)
{
_i = static_cast<int>(i);
}
int _i;
};
int main()
{
Float f2 = 10;
Int i2 = 10;
return 0;
}
If you're worried about the implicit calls to the constructor you can make it explicit
struct Float
{
explicit Float(int i)
{
_f = static_cast<float>(i);
}
float _f;
};
int main()
{
Float f2 = Float(10);
return 0;
}
The readability of the code is affected if the function with same name and the same type of input arguments can produce different return types.

Initialize const multidimensional array in class initializer list from constructor arguments

I have a class that includes a const 2d array of values, and I want to define this array when I call the constructor. I have been told using const on values that should never be changed is preferred, so I wanted to try it in this case.
class A {
public:
A(const int passedArray[2][2]) : memberArray(passedArray) {}
private:
const int memberArray[2][2];
};
const int passedArray[][2] = {
{0,0},
{0,1}
};
A a(passedArray); // fails with "incompatible types
//in assignment of 'const int (*)[2]' to 'const in[2][2]'
A a(&passedArray); // fails
This also fails with const int passedArray[2][2] = ..., with private: const int** memberArray, etc.
I know I have to use an initializer list because a constructor cannot change values of const. Is this possible at all on C++11?
Comments to your question has some good info.
After that here is the working code:
//g++ 5.4.0
#include <iostream>
class A {
public:
A(int passedArray[2][2])
{
//USE STD COPY TO COPY THE ARRAYS.
std::copy(&passedArray[0][0], &passedArray[0][0]+4,&memberArray[0][0]);
//PRINT VALUES TO TEST
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
std::cout << memberArray[i][j] << std::endl;
}
}
}
private:
int memberArray[2][2];
};
int main()
{
//INITIALIZE YOUR ARRAY
int passedArray[2][2] = {
{0,0},
{0,1}
};
//CREATE OBJECT
A a(passedArray);
}
If your business need is to have a "const multi dimensional array in your class"
you have to do it any one of the below ways.
class A {
public:
A(const int passedArray[2][2])
{
}
private:
const int memberArray[2][2] = {{5,6},{7,8}}; //INITIALIZE HERE
};
OR
class A {
public:
A(const int passedArray[2][2])
{
}
private:
//DECLARE STATIC HERE
static const int memberArray[2][2];
};
//INTIALIZE HERE
const int A::memberArray[2][2] = {{5,6},{7,8}};

Non-const used in a constexpr : what does the standard say?

What does the C++11 iso standard say about such an expression :
class MyClass
{
public:
constexpr int test()
{
return _x;
}
protected:
int _x;
};
_x is a non-const used in a constexpr : will it produce an error, or will the constexpr be simply ignored (as when we pass a non-const parameter) ?
It's perfectly fine, though somewhat useless:
constexpr int n = MyClass().test();
Since MyClass is an aggregate, value-initializing it like that will value-initialize all members, so this is just zero. But with some polish this can be made truly useful:
class MyClass
{
public:
constexpr MyClass() : _x(5) { }
constexpr int test() { return _x; }
// ...
};
constexpr int n = MyClass().test(); // 5
If the expression does not resolve to a constant expression, then it cannot be used as such. But it can still be used:
#include <array>
constexpr int add(int a, int b)
{
return a+b;
}
int main()
{
std::array<int, add(5,6)> a1; // OK
int i=1,
int j=10;
int k = add(i,j); // OK
std::array<int, add(i,j)> a2; // Error!
}

Initializing constant array of fixed size inside class

Consider the following class:
class A {
const int arr[2];
public:
A() { }
};
Is it possible to initialize arr from the constructor initializer list or in any other way than on the line where it is declared (i.e. const int arr[2] = {1,2};)?
Note that I'm interested in methods that work with C++98!
By wrapping them in a struct, e.g.:
class A
{
struct Data
{
int arr[2];
};
Data const arr;
public:
A() : arr( someOtherStruct ) {}
};
This does mean that to access the data, you'd have to write arr.arr.
It's possible to avoid that by inheriting from the struct:
struct PrivateDataForA
{
int arr[2];
};
class A : private PrivateDataForA
{
public:
A() : PrivateDataForA( someOtherStruct ) {}
};
This does make the name of the struct visible outside of the class
(which might be an advantage—client code could pass you one as an
argument).
If you don't have an instance of the struct handy, say because you want
to fill it with values calculated from arguments to the constructor, you
can use a static member function:
class A : private PrivateDataForA
{
static PrivateDataForA createInitializer( int a, int b );
public:
A( int a, int b ) : PrivateDataForA( createInitializer( a, b ) )
{
}
};
For the OP’s concrete example:
#include <iostream>
#include <stddef.h>
typedef ptrdiff_t Size;
typedef Size Index;
template< class Element, Size n >
struct Array{ Element elem[n]; };
class A {
Array<int, 2> const arr_; // const int arr[2];
A& operator=( A const& ); // No such.
static Array<int, 2> const& oneAndTwo()
{
static Array<int, 2> const a = {1, 2};
return a;
}
public:
A(): arr_( oneAndTwo() ) {}
int at( Index i ) const { return arr_.elem[i]; }
};
int main()
{
using namespace std;
A o;
for( int i = 0; i < 2; ++i )
{
cout << o.at( i ) << endl;
}
}
Initializing array elements to non-zero values requires C++11 support.
In C++03, it's only possible to value-initialize your array, resulting in each element's value being 0:
class A {
const int arr[2];
public:
A() : arr() { }
};
For the relevant C++03 standardese, see this question and answer:
How can i use member initialization list to initialize it?
(I'm going to assume that by C++98 you mean not C++11, i.e. that C++03 is acceptable. If this assumption is wrong, please say so.)
No. It's not.