array initialization requires a brace-enclosed initializer list lambda - c++

I'm new to lambda expression and little confused why I'm getting the error here?
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int arr[] = { 11, 21, 4, 13 };
for_each(arr, arr + 4, [arr](int x) {
cout << x;
});
return 0;
}
I just add LAMBDA for this function.
void fun1(int x)
{
cout << x << " ";
}
Here is the error message on visual studio.
'main::<lambda_4ee0815d3a456ed46cc70a2a94c10f76>::arr':
array initialization requires a brace-enclosed initializer list Project1

You cannot copy arrays, so you can capture arr by reference instead if you actually need it:
for_each(arr, arr + 4, [&arr](int x) { cout << x; });
// ^^^
However, since you don't refer to the array in the lambda body, you don't need to capture it at all:
for_each(arr, arr + 4, [](int x) { cout << x; });
// ^^^^

Related

Foreach loop with multidimensional arrays in c++

I am getting an error while compiling the following cpp code:
int x[][2]{{1, 2}, {3, 4}};
for (int e[2] : x) {
std::cout << e[0] << ' ' << e[1] << '\n';
}
This gives the following error:
error: array must be initialized with a brace-enclosed initializer
I did replaced int e[2] with auto e and that worked but I want to work with the actual type.
Is there any workaround?
the correct fixed-size declaration is
for (int(&e)[2] : x) {}
or you can use auto& to deduce it
for (auto& e : x) {} // same as above
note: auto doesn't deduce the same type
for (auto e : x) {} // e is int*
interpret the inner array as a pointer:
#include <iostream>
int main() {
int x[][2]{{1, 2}, {3, 4}};
for (int* e : x) {
std::cout << e[0] << ' ' << e[1] << '\n';
}
}

How to directly specify some values as an argument in C++ instead of specifying an array name or a pointer to an array

Can I write a function in C++ to accept an array of values like this:
void someFunction(/*the parameter for array*/){
//do something
}
someFunction({ 1, 2, 3 });
There are various ways of doing this.
Method 1
Using initializer_list as parameter type.
void someFunction(std::initializer_list<int> init){
}
int main()
{
someFunction({ 1, 2, 3 });
}
Method 2
Using std::vector<int> as parameter type.
void someFunction(const std::vector<int> &init){
}
int main()
{
someFunction({ 1, 2, 3 });
}
You could get inspiration from e.g. std::min and use std::initializer_list
void someFunction(std::initializer_list<int> ints) {
for (int i : ints)
{
std::cout << i << '\n';
}
}
Yes you can.
One option is to use std::vector, and in your specific case std::vector<int> const& for the parameter of someFunction:
#include <iostream>
#include <vector>
void someFunction(std::vector<int> const & a)
{
for (int i : a)
{
std::cout << i << ", ";
}
std::cout << std::endl;
}
int main()
{
someFunction({ 1, 2, 3 });
return 0;
}
Output:
1, 2, 3,

Is it possible to use iterator in C array?

I know iterator can be used for vector either with std::vector::begin or with std::begin defined in <iterator>. Same for std::end.
Can I also use iterators with C arrays? I tried the following but it didn't work.
#include <iostream>
#include <iterator>
using std::cin;
using std::cout;
using std::endl;
using std::begin;
using std::end;
void print(const int *arr) {
for (auto cbeg = cbegin(arr); cbeg != cend(arr); ++cbeg) {
cout << *cbeg << endl;
}
}
int main() {
int arr[] = {9, 18, 31, 40, 42};
print(arr);
}
edit:
I thought i could do this because of this piece of code in C++ primer where they used begin and end to get iterators to first and to one past the end element:
#include <iterator>
using std::begin; using std::end;
#include <cstddef>
using std::size_t;
#include <iostream>
using std::cout; using std::endl;
// const int ia[] is equivalent to const int* ia
// size is passed explicitly and used to control access to elements of ia
void print(const int ia[], size_t size)
{
for (size_t i = 0; i != size; ++i) {
cout << ia[i] << endl;
}
}
int main()
{
int j[] = { 0, 1 }; // int array of size 2
print(j, end(j) - begin(j));
return 0;
}
Yes, iterators can be used on arrays. For example
int main()
{
int arr[] = {9, 18, 31, 40, 42};
for (auto cbeg = cbegin(arr); cbeg != cend(arr); ++cbeg) {
cout << *cbeg << endl;
}
will print all elements of arr.
The problem is that, your print() function accepts a pointer, so iterators cannot be used in that case.
However, if you change print() to
void print(int(&arr)[5])
{
// same body as before
}
or (if you don't want the size fixed as 5) to
template<int N> void print(int(&arr)[N])
{
// same body as before
}
you will find it will work, since the array is passed by reference. Note that these functions will not compile if pointers are passed to them.
You can use std::begin and std::end on c-style arrays. You can't use them on pointers. C-style arrays decay to pointers when passed to functions unless you pass them by reference. Dynamic arrays (allocated by new) are also accessed via a pointer, so that doesn't work either.
Passing by reference like void print(int (&arr)[5]) {...} should work. Remark that you need templates if you want variable sized arrays.
You seem to be looking for
// use array pointer to dodge array decay of function parameters:
void obfuscated_meta_programming (int (*arr)[5])
{
for(auto it = std::begin(*arr); it != std::end(*arr); it++)
{
cout << *it << endl;
}
}
int main()
{
int arr[] = {9, 18, 31, 40, 42};
obfuscated_meta_programming(&arr);
}
Which can be rewritten in a sane way like this:
void print (int arr[5])
{
for(size_t i=0; i<5; i++)
{
cout << arr[i] << endl;
}
}
int main()
{
int arr[] = {9, 18, 31, 40, 42};
print(arr);
}
Not this way. Your function print gets only const int * pointer. This pointer has no information about the length of array arr[] from function main, so if you have pointer to int as parameter, then even theoretically, there is no way you could iterate in function "print", regardless whether you use iterator or not. One way to go would be to use std::array and initialize it with char[], like this:
#include <iterator>
#include <iostream>
#include <array>
using std::cin;
using std::cout;
using std::endl;
template<size_t N> void print(std::array<int,N> &arr) {
for (const auto &s : arr) {
cout << s << endl;
}
}
int main() {
std::array<int,5> arr = {9, 18, 31, 40, 42};
print(arr);
}
Compile with --std=c++11
C arrays are not length prefixed. If you have the size, you can create a pointer which satisfies Iterator requirements:
begin = arr;
end = arr + size;
some_algorithm(begin, end);

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;
}

no matching function for call to ‘begin(int**&)’

I wrote a c++ program as fllow(3.43.cpp):
#include <iostream>
using std::cout;
using std::endl;
void version_1(int **arr) {
for (const int (&p)[4] : arr) {
for (int q : p) {
cout << q << " ";
}
cout << endl;
}
}
int main() {
int arr[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
version_1(arr);
return 0;
}
Then I compile it by using: gcc my.cpp -std=c++11, there is an error I can not deal with.
Info:
3.43.cpp:6:30: error: no matching function for call to ‘begin(int**&)’
for (const int (&p)[4] : arr) {
^
3.43.cpp:6:30: note: candidates are:
In file included from /usr/include/c++/4.8.2/bits/basic_string.h:42:0,
from /usr/include/c++/4.8.2/string:52,
from /usr/include/c++/4.8.2/bits/locale_classes.h:40,
from /usr/include/c++/4.8.2/bits/ios_base.h:41,
from /usr/include/c++/4.8.2/ios:42,
from /usr/include/c++/4.8.2/ostream:38,
from /usr/include/c++/4.8.2/iostream:39,
from 3.43.cpp:1:
/usr/include/c++/4.8.2/initializer_list:89:5: note: template<class _Tp> constexpr const _Tp* std::begin(std::initializer_list<_Tp>)
begin(initializer_list<_Tp> __ils) noexcept
I search it in google, but not find similar answer.
Since arr is just a pointer, there's no way to deduce how big it is. But, since you are actually passing in a real array, you can just template your function on its dimensions so you take the actual array by reference rather than having it decay to a pointer:
template <size_t X, size_t Y>
void foo(const int (&arr)[X][Y])
{
std::cout << "Dimensions are: " << X << "x" << Y << std::endl;
for (const int (&row)[Y] : arr) {
for (int val : row) {
std::cout << val << ' ';
}
std::cout << std::endl;
}
}
int main() {
int arr[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
foo(arr);
}
std::begin() and std::end() won't work for pointers. They only work for arrays. If you want to deduce the size of your array you'll need to pass it as a reference your function:
#include <cstddef>
template <std::size_t A, std::size_t B>
void version_1(int (&arr)[B][A]) {
for (const int (&p)[A] : arr) {
for (int q : p) {
cout << q << " ";
}
cout << '\n';
}
}
Pointers are not the same as arrays. To be able to use range based for, your container must support std::begin and std::end. Standard C arrays can be used, but not pointers.