C++: array<> too many initializers - c++

The following code is returning the compilation error below. I'm stuck understanding how there are too many initializers. This code works using vector<X>. Does anyone know why the error is being reported and how to resolve? Thanks
#include <iostream>
#include <array>
using namespace std;
struct X {
int x, y;
};
int main(int argc, char *argv[])
{
array<X,2> a0 = {{0,1}, {2,3}};
for (auto& p : a0) {
cout << p.x << endl;
cout << p.y << endl;
}
return 0;
}
Compilation:
g++ -pedantic -Wall test116.cc && ./a.out
test116.cc: In function ‘int main(int, char**)’:
test116.cc:11:34: error: too many initializers for ‘std::array<X, 2>’
array<X,2> a0 = {{0,1}, {2,3}};

Try
array<X,2> a0 = {{{0,1}, {2,3}}};
Note the extra set of braces.
It seems a bit odd but it's this way because the only member of array is the actual array:
template <class T, size_t N>
class array {
T val[N];
// ...
};
The constructors are all implicitly defined so that array ends up being a trivially constructable type.

You may use one of the following initializations because std::array is an aggregate that contains another aggregate as its data member.
array<X,2> a0 = { { { 0, 1 }, { 2, 3 } } };
array<X,2> a0 = { 0, 1, 2, 3 };
array<X,2> a0 = { { 0, 1, 2, 3 } };
array<X,2> a0 = { { 0, 1, { 2, 3 } } };
array<X,2> a0 = { { { 0, 1 }, 2, 3 } };

I found that my problem is related to the version of g++,9.4.0 is ok and 5.4.0 not.version of g++.By the way, the version of g++ is associated with the system version generally.

Related

Get two arrays from function and store them in different data type array in C++

I have a function which contains more than one array and I want to use those two arrays in my main function in this way
void fun () //which data type should I place here int OR char ?
{
int array[4]={1,2,3,4}
char array2[3]={'a','b','c'}
return array,array2;
}
int main(){
int array1[4];
char array2[3];
array1=fun(); is it possible to get these array here ?
array2=fun();
}
If you really want to return arrays, you could put them in a std::pair of std::arrays:
#include <array>
#include <utility>
auto fun() {
std::pair<std::array<int, 4>, std::array<char, 3>> rv{
{1, 2, 3, 4},
{ 'a', 'b', 'c' }
};
return rv;
}
int main() {
auto[ints, chars] = fun();
}
Use std::tuple of std:arrays:
#include <iostream>
#include <array>
#include <tuple>
std::tuple<std::array<int, 4>, std::array<char, 3>> fun()
{
std::array<int, 4> a1 = { 1, 2, 3, 4 };
std::array<char, 3> a2 = { 'a', 'b', 'c' };
return std::make_tuple(a1, a2);
}
int main()
{
auto mixedArrays = fun();
for (const auto& i : std::get<0>(mixedArrays))
{
std::cout << i << std::endl;
}
for (const auto& i : std::get<1>(mixedArrays))
{
std::cout << i << std::endl;
}
}
Demo
This way you can extend the code to make fun() return more stuff in the future if need be.
Using a struct, code would look like this (using range based for loops for output).
#include <array>
#include <iostream>
// struct holding two arrays with clear names
struct myfun_retval_t
{
std::array<int, 4> integers;
std::array<char, 3> characters;
};
// function returning the struct with two arrays
myfun_retval_t myfun()
{
myfun_retval_t retval
{
{1,2,3,4},
{'a','b','c'}
};
return retval;
}
int main()
{
// call function and store result
auto retval = myfun();
// then output content, using clear readable names for the arrays
for (const int value : retval.integers)
{
std::cout << value << " ";
}
std::cout << "\n";
for (const char c : retval.characters)
{
std::cout << c << " ";
}
return 0;
}
Pass pointers to your arrays in main to your function
Like this
void fun(int* array, char* array2)
{
...
}
int main()
{
int array1[4];
char array2[3];
fun(array1, array2);
}
Hopefully that will get you started, but really you need to read about arrays and pointers and function parameters in your C++ book. This is a complicated topic, and one that many newbies get wrong.

Brace-enclosed initializer for matrix constructor fail in type std::complex<double> >

I implented a contructor for my matrix class to do brace-enclosed initialization using nested std::initializer_list. The constructor works fine for primary type: `int`, `double`; but renders error-reading for `complex`. How to fix this error reading?
The matrix class
template <typename T> class xxx
{
public:
T *ptr;
int col, row, size;
xxx() = delete;
xxx(const int i, const int j):row(i), col(j), size(i*j)
{
ptr = new T [this->size] ;
}
xxx(const std::initializer_list< std::initializer_list<T> > s):xxx(s.size(), s.begin()->size())
{
int j = 0;
for (const auto& i : s) { std::copy (i.begin(), i.end(), ptr + j*col); ++j ; }
}
~xxx() {delete [] this->ptr;}
T operator()(const int i, const int j) const { return ptr[i*col+j]; }
};
A typical ouput overload is added here for complete.
template <typename X> std::ostream& operator<<(std::ostream&p, const xxx<X>&a)
{
for (int i=0; i<a.row; i++) {
for (int j=0; j <a.col; j++) p << std::setw(6) << a(i, j);
p << std::endl;
}
return p;
}
The first test main() with type `double` works well.
#include <iostream>
#include <initializer_list>
#include <iomanip>
#include <complex>
int main()
{
xxx<double> x = {{1, 2,3,4} , {3, 4,5,6}, {5, 6,7,8} };
std::cout << x << std::endl;
}
It prints what is expected:
$ ./a.exe
1 2 3 4
3 4 5 6
5 6 7 8
Then, I try with another type of my interested, `complex`:
int main()
{
xxx< std::complex<double> > z = { {(1,2), (3,4)}, {(5,6), (7,8)} };
std::cout << z << std::endl;
}
The outpur is wrong as follows:
$ ./a.exe
(2,0) (4,0)
(6,0) (8,0)
The imaginery part is missing, and the real parts are taking values of the counter imaginery part. Any idea or suggestion will be highly appreciated.
Your problem is not related to the initializer list. The problem is that this code
#include <iostream>
#include <complex>
int main()
{
std::complex<double> x = (1,2);
std::cout << x;
}
Is not doing what you expect it to do. Output is
(2,0)
Because (1,2) is the comma operator at work. std::complex<double> x = (1,2); is the same as std::complex<double> x = 2;.
You need to use curly braces for initialization:
#include <iostream>
#include <complex>
int main()
{
std::complex<double> x = {1,2};
std::cout << x;
}
Output
(1,2)
PS I would strongly advise you to use a std::vector<T> to hold the data rather than a T*. Currently copying a xxx will cause undefined behavior, due to not following the rule of 3/5.

List initialization of const and array structure fields

Just recently started C++ programming for micro-controllers, and I've ran into situations* where it would be convenient to have a non-static const field on a struct that is always guaranteed to have a fixed value (same for every instance of the sturct, ever).
Given a struct
struct S {
const uint8_t c; // Should always be 42
char v;
uint32_t arr[4];
}
I'd like c to be a constant value, and the same constant value every time. I would love to be able to use the convenience of brace initializer lists, for setting v and the members of arr like
S some_var = {'v', { 0, 1, 2, 3 } };
Since I'd like c to be a constant, I'm under the impression that I have to use an initializer list for setting c, such as S() : c(42) {}, which works just fine, as long as I don't try to also initialize arr, in which case I'm lost on how the list should look like. Is this doable using C++11? (Also interested in an answer if this is not doable in C++11, but in some newer standard.)
Example code:
#include <stdio.h>
#include <stdint.h>
struct S {
const uint8_t c; // Should always be 42 on every instance
// of the struct due to hardware shenanigance
// (i.e. this struct is the representation of a register value)
char v;
uint32_t arr[4];
// This allows using "S s1;"
S() : c(42), v('a'), arr{} {}
// This allows using "S s2 = { 'v', 0, 1, 2, 3 };" works but it's clumsy:
S(uint32_t v, uint32_t arr0, uint32_t arr1, uint32_t arr2, uint32_t arr3) :
c(42), v(v), arr{ arr0, arr1, arr2, arr3 } {}
// I would like to do something along the lines of "S s2 = { 'v', { 0, 1, 2, 3 } };":
// S(uint32_t v, uint32_t arr[4] /*?*/) :
// c(42), v(v), arr{/*?*/} {}
};
// Main just for the sake of completeness
int main() {
// Works just fine
S s1;
printf("s1.c = %u\n", s1.c); // 42
printf("s1.v = '%c'\n", s1.v); // a
printf("s1.arr[3] = %u\n", s1.arr[3]); // 0
// Initialiation like this works with the line:12 signature:
S s2 = { 'v', 0, 1, 2, 3 };
// I'd like to initialize like this:
// S s2 = { 'v', { 0, 1, 2, 3 } };
printf("s2.c = %u\n", s2.c); // 42
printf("s2.v = '%c'\n", s2.v); // v
printf("s2.arr[3] = %u\n", s2.arr[3]); // 3
return 0;
}
*Context on why I'd want to do this: This might seem like a weird thing to want, since if the value is always the same, why bother storing it? Well imagine that the struct in question is a bitfield which corresponds to the register of an IC with which the micro-controller communicates. These registers sometimes have "reserved" fields, and the datasheet specifies what value you must write into these fields. From a programmer's point of view, it would be convenient if I never had to deal with setting said bits manually.
C++11 gives you std::array which is like a raw array, but comes with none of the "negatives" (array decay, can't copy). Using that you can get exactly what you want like
struct S {
const uint8_t c = 42;
char v = 'a';
std::array<uint32_t, 4> arr{};
// This allows using "S s1;"
S() {}
S(uint32_t v, std::array<uint32_t, 4> arr) : v(v), arr{arr} {}
};
// Main just for the sake of completeness
int main() {
// Works just fine
S s1;
printf("s1.c = %u\n", s1.c); // 42
printf("s1.v = '%c'\n", s1.v); // a
printf("s1.arr[3] = %u\n", s1.arr[3]); // 0
S s2 = { 'v', { 0, 1, 2, 3 } };
printf("s2.c = %u\n", s2.c); // 42
printf("s2.v = '%c'\n", s2.v); // v
printf("s2.arr[3] = %u\n", s2.arr[3]); // 3
return 0;
}
which outputs
s1.c = 42
s1.v = 'a'
s1.arr[3] = 0
s2.c = 42
s2.v = 'v'
s2.arr[3] = 3
If you absoluytley have to have a raw array in S then your other option is to use a std::initializer_list in the constructor. That would look like
struct S {
const uint8_t c = 42;
char v = 'a';
uint32_t arr[4]{};
// This allows using "S s1;"
S() {}
S(uint32_t v, std::initializer_list<uint32_t> data) : v(v)
{
int i = 0;
for (auto e : data)
arr[i++] = e;
}
};
// Main just for the sake of completeness
int main() {
// Works just fine
S s1;
printf("s1.c = %u\n", s1.c); // 42
printf("s1.v = '%c'\n", s1.v); // a
printf("s1.arr[3] = %u\n", s1.arr[3]); // 0
S s2 = { 'v', { 0, 1, 2, 3 } };
printf("s2.c = %u\n", s2.c); // 42
printf("s2.v = '%c'\n", s2.v); // v
printf("s2.arr[3] = %u\n", s2.arr[3]); // 3
return 0;
}
And you get the same results as the code using std::array.

Define a enum-variabele after declaration

I'm learning enumerations. I have the following problem: I don't understand, why this works:
enum {fahrrad = 1, Auto = 2} einFahrzeug;
int main() {
einFahrzeug = fahrrad;
but this doesn't:
enum {fahrrad = 1, Auto = 2} einFahrzeug;
einFahrzeug = fahrrad;
int main() { ...
I would be very happy about an answer
You can't assign stuff to variables outside of a function. More simple example:
#include <iostream>
int x;
x = 42;
int main()
{
std::cout << x << '\n';
}
This gives:
prog.cpp:4:1: error: ‘x’ does not name a type
x = 42;
^
Try it with ideone.com: https://ideone.com/A1K06A

C++11 for loop in a Template Function

I am trying to write a function which would Print Data on the console. The function is to be templated as it should accept different types of Data.
The code is as shown below:
template<typename DataType>
void PrintData(DataType *X)
{
for (DataType Data : X)
{
cout << Data << "\t";
}
cout << endl;
}
int main()
{
int nArray[7] = { 7, 5, 4, 3, 9, 8, 6 };
double dArray[5] = { 4.3, 2.5, -0.9, 100.2, 3.0 };
PrintData(nArray);
PrintData(dArray);
system("pause");
return EXIT_SUCCESS;
}
I get an error that variable Data is undeclared in the templated function PrintData.
error C2065: 'Data' : undeclared identifier
error C3312: no callable 'begin' function found for type 'double *'
error C3312: no callable 'begin' function found for type 'int *'
error C3312: no callable 'end' function found for type 'double *'
error C3312: no callable 'end' function found for type 'int *'
Any help would be appreciated.
Thanks
Assuming you have included the iostream header file and the using namespace std; directive. Then your problems are:
You should not use DataType *. Your code makes X a pointer, which is different from array. Use DataType const& or DataType&& instead.
You have to include the iterator header file which provides the begin and end function for C-style array.
The following code works for me.
#include <iostream>
#include <iterator>
using namespace std;
template<typename DataType>
void PrintData(DataType const& X)
{
for (auto Data : X)
{
cout << Data << "\t";
}
cout << endl;
}
int main()
{
int nArray[7] = { 7, 5, 4, 3, 9, 8, 6 };
double dArray[5] = { 4.3, 2.5, -0.9, 100.2, 3.0 };
PrintData(nArray);
PrintData(dArray);
return EXIT_SUCCESS;
}
As commented by Igor Tandetnik, you may use template<struct DataType, size_t N> if you want to refer the size of the array.
Update:
With template<struct DataType> and DataType *X, DataType is deduced as int and double, and X is a pointer which is not a container.
With template<struct DataType, size_t N> and DataType (&X)[N], DataType is deduced as int and double, and X is an array which can be used with range-based for loop.
With template<struct DataType> and DataType&& X or DataType const& X, DataType is deduced as int[7] or double[5], and X is an array as well.
The problem is that you're passing the name of the array (e.g., nArray), which is just a pointer to the first element, basically. However, new-style for loops expect something on which you can call begin and end - a range.
The following changes make it work by using a vector instead of an array. Note that there are very few differences otherwise, and, in general, very few reason to use C-style arrays in contemporary C++.
#include <iostream>
#include <vector>
using namespace std;
template<typename DataType>
void PrintData(const DataType &X)
{
for (const auto &Data : X)
{
cout << Data << "\t";
}
cout << endl;
}
int main()
{
vector<int> nArray = { 7, 5, 4, 3, 9, 8, 6 };
vector<double> dArray = { 4.3, 2.5, -0.9, 100.2, 3.0 };
PrintData(nArray);
PrintData(dArray);
system("pause");
return EXIT_SUCCESS;
You have some problems:
1) DataType must be a container. So, try to use:
std::vector<int> nArray = { 7, 5, 4, 3, 9, 8, 6 };
std::vector<double> dArray = { 4.3, 2.5, -0.9, 100.2, 3.0 };
2) You are not going to change the container. It's better to pass container by const reference:
template<typename DataType>
void PrintData(const DataType & X);
3) Change the loop like this:
for (const auto & value : X) {
std::cout << value << "\t";
}
Code example:
#include <iostream>
#include <vector>
template<typename DataType>
void PrintData(const DataType & X) {
for (const auto & value : X) {
std::cout << value << "\t";
}
std::cout << std::endl;
}
int main() {
std::vector<int> nArray = { 7, 5, 4, 3, 9, 8, 6 };
std::vector<double> dArray = { 4.3, 2.5, -0.9, 100.2, 3.0 };
PrintData(nArray);
PrintData(dArray);
return 0;
}
As Igor suggested, If at all you wish to use DataType * then you need to do something like this
#include <iostream>
#include <iterator>
using namespace std;
template <typename DataType, size_t N>
void PrintData(DataType (&X)[N])
{
for (auto i : X)
cout << i << "\t";
cout << endl;
}
int main()
{
int nArray[7] = { 7, 5, 4, 3, 9, 8, 6 };
double dArray[5] = { 4.3, 2.5, -0.9, 100.2, 3.0 };
PrintData(nArray);
PrintData(dArray);
return EXIT_SUCCESS;
}
Output
7 5 4 3 9 8 6
4.3 2.5 -0.9 100.2 3
Explanation:
If you see void PrintData(int* nArray); & void PrintData(int (&nArray)[7] );
are similar declarations, except that seconds one tells where array ends.
Template function
template <typename DataType, size_t N>
void PrintData(DataType (&X)[N])
is deduced as'
void PrintData(int (&nArray)[7] )
You could also write
void PrintData(int (&nArray)[7] )
{
for (auto i : nArray)
cout << i << "\t";
cout << endl;
}