I keep getting a compilation error if I use an array passed as parameter to a method on std::begin or std::end such as this:
#include <iostream>
#include <algorithm>
using namespace std;
class Test
{
public:
static bool exists(int ints[], int size, int k)
{
if (std::find(std::begin(ints), std::end(ints), k) != std::end(ints)) {
return true;
}
return false;
}
};
I tried casting it to &int[0] but it will still not compile.
The parameter ints is not an array, so you aren't passing an array into std::begin / std::end in the example. A function parameter is never an array in C++. When you declare a function array to be an array such as in your example, that parameter is adjusted to be a pointer to the element of such array. In your case, the type of the parameter ints has been adjusted to be a pointer to int i.e. int*, and you cannot pass a pointer into std::begin / std::end, as the error message surely explains.
You have passed the size as another parameter, so you could instead use:
std::find(ints, ints + size, k)
A more modern API design is to wrap the pointer and the size into a single class. The C++20 standard library comes with such class template: std::span. It also has convenient range algorithms that are quite convenient:
static bool exists(std::span<const int> ints, int k)
{
if (std::ranges::find(ints, k) != std::end(ints)) {
Even moreso, C++20 standard library has a function template that makes your function unnecessary:
std::ranges::contains(some_array, k);
Use std::span.
try this:
#include <algorithm>
#include <iostream>
#include <span>
bool exists(std::span<int> span, int needle) {
return std::find(span.begin(), span.end(), needle) != span.end();
}
int main() {
int arr[] = {0, 1, 2, 3, 4};
bool ok = exists(arr, 3);
if (ok) {
std::cout << "ok" << '\n';
} else {
std::cout << "not ok" << '\n';
}
return 0;
}
Here is a working example.
#include <iostream>
#include <vector>
bool exists(int x[], const int size, const int k)
{
std::vector<int> v(x, x + size);
if (std::find( v.begin(), v.end(), k) != v.end()) {
return true;
}
return false;
}
int main()
{
int const sz = 10;
int arrayi[sz] = { 1, 2, 3,4 ,5 ,6 ,7 , 8, 9, 0 };
if (exists(arrayi, sz, 4))
std::cout << "exist" << std::endl;
else
std::cout << "it does not" << std::endl;
}
I want an array that have new attributed values if the value is x.
I can do that in PHP with that code:
$test = array(1=>55, 2=>66);
on above code if test[0] = 1, the new value of test[0] is going to be 55.
I want to do that in C++.
Normal C++ arrays do not have keys. There are always 0-indexed.
But we have std::map which is what PHP also use internally for key-based containers.
https://en.cppreference.com/w/cpp/container/map
You can make your own attributed values class in C++, so it has that behavior.
You can make it so the behavior is hard coded into the class. Or if you want to get fancier you can make the class having a value mapping passed in.
Here's an example with the value mapping passed into the class.
#include <cstddef>
#include <iostream>
#include <map>
#include <stdexcept>
#include <vector>
using sad_panda = std::logic_error;
using std::cout;
using std::map;
using std::size_t;
using std::vector;
namespace {
class AttributedValues {
vector<int> v;
map<int, int> attr_to_value;
public:
AttributedValues(map<int, int> mapping);
void set(size_t index, int value);
int operator[](size_t index) const;
};
AttributedValues::AttributedValues(map<int, int> mapping)
: attr_to_value{mapping}
{ }
void AttributedValues::set(size_t index, int value) {
if (index >= v.size()) {
v.resize(index+1);
}
auto iter = attr_to_value.find(value);
if (iter != attr_to_value.end()) {
value = iter->second;
}
v[index] = value;
}
int AttributedValues::operator[](size_t index) const {
if (index >= v.size()) {
throw sad_panda("AttributedValues::operator[] index out of range");
}
return v[index];
}
} // anon
int main() {
auto test = AttributedValues{{{1, 55}, {2, 66}}};
test.set(0, 1);
test.set(10, 2);
cout << test[0] << "\n";
cout << test[10] << "\n";
}
I'd like to be able to declare an array as a function argument in C++, as shown in the example code below (which doesn't compile). Is there any way to do this (other than declaring the array separately beforehand)?
#include <stdio.h>
static void PrintArray(int arrayLen, const int * array)
{
for (int i=0; i<arrayLen; i++) printf("%i -> %i\n", i, array[i]);
}
int main(int, char **)
{
PrintArray(5, {5,6,7,8,9} ); // doesn't compile
return 0;
}
If you're using older C++ variants (pre-C++0x), then this is not allowed. The "anonymous array" you refer to is actually an initializer list. Now that C++11 is out, this can be done with the built-in initializer_list type. You theoretically can also use it as a C-style initializer list by using extern C, if your compiler parses them as C99 or later.
For example:
int main()
{
const int* p;
p = (const int[]){1, 2, 3};
}
It's allowed with a typecast in C++11 and in extern "C" with C99:
void PrintArray(size_t len, const int *array)
{
for(size_t i = 0; i < len; i++)
printf("%d\n", array[i]);
}
int main(int argc, char **argv)
{
PrintArray(5, (const int[]){1, 2, 3, 4, 5});
return 0;
}
This compiles, but I wouldn't recommend it.
#include <stdio.h>
struct arr
{
int array[5];
};
static void PrintArray(int arrayLen, arr array)
{
for (int i=0; i<arrayLen; i++) printf("%i -> %i\n", i, array.array[i]);
}
int main(int, char **)
{
PrintArray(5, (arr){5,6,7,8,9});
return 0;
}
Disclaimer: For this answer I get some downvotes, but it originates from 2009, where C++ 11 was about to be defined. For modern C++ please scroll below.
Well, try using boost...
Here is the solution using the boost::assign library and bit more C++ like programming ;)
#include <boost/assign/list_of.hpp>
#include <iostream>
#include <algorithm>
namespace
{
template<class CollectionT>
void print(CollectionT const& coll)
{
std::ostream_iterator<int> out(std::cout, ", ");
std::copy(coll.begin(), coll.end(), out);
}
}
int main()
{
using namespace boost::assign;
print( list_of(1)(2)(3)(4)(5) );
return 0;
}
C++ 11 and higher with the explanation of particular features
Complied with clang:
clang++ -std=c++14 -I /usr/local/include/ main.cpp
#include <boost/assign/list_of.hpp>
#include <iostream>
#include <iterator>
#include <algorithm>
#include <initializer_list>
template<typename CollectionT, typename OStream>
auto // <- auto result type deduction from C++ 14
make_output_iterator(CollectionT const& coll, OStream& out)
{
return std::ostream_iterator<typename CollectionT::value_type>(out, ", ");
}
// here template specialization is used, to demonstrate initializer lists from C++ 11
template<typename T>
void print(std::initializer_list<T> items)
// ^----------------------^ passed by value due to move semantics
{
using namespace std;
cout << "printing an initializer list: ";
copy(items.begin(), items.end(), make_output_iterator(items, cout));
cout << endl;
}
template<typename CollectionT>
void print(CollectionT const& items)
{
using namespace std;
cout << "printing another collection type: ";
copy(items.begin(), items.end(), make_output_iterator(items, cout));
cout << endl;
}
int main()
{
print({0,1,2,3,4,5,6,7,9});
using namespace boost::assign;
print( list_of(0)(1)(2)(3)(4)(5)(6)(7)(8)(9) );
}
Starting from C++11, you can just use std::begin(std::initializer_list const&) to get the pointer. Example:
#include <iostream>
#include <iterator>
void func(int len, const int* x)
{
for(int i=0;i<len;++i)
std::cout << x[i] << "\n";
}
int main()
{
func(5, std::begin({1,3,6,823,-35}));
}
Unlike the accepted answer, this is really Standard-compatible code.
With C++0x you could use an std::initializer_list (and a foreach loop)
#include <iostream>
#include <initializer_list>
void print (const std::initializer_list<int>& array)
{
for (auto x : array) // C++0x foreach loop
std::cout << x << std::endl;
}
int main (int argc, char ** argv)
{
print ({ 1, 2, 3, 4, 5 });
}
Yes and no. In the current version of the standard (ISO C++ 1998 with ammendments from 2003), it is not possible. However, in the next version of the standard "C++0x" (which, despite its name implying that it will be released in 200x, will most likely be released in 2010), it will be possible with std::initializer_list<>.
You can use std::initializer_list list Joe D suggests, however I am not sure you can use it if you want other parameters. (I can't seem to find any information on that.) However, if you declare a const reference to a vector, the initializer_list that is created with { ... } will get converted to the vector.
#include <iostream>
#include <vector>
void PrintArray(const char* prefix, const std::vector<int>& array)
{
std::cout << prefix << std::endl;
for (int i : array) {
std::cout << i << std::endl;
}
}
int main(int, char **)
{
PrintArray("test array", {5,6,7,8,9} );
return 0;
}
You could use a variable number of arguments instead of passing an array:
static void PrintArray(int arrayLen, ...)
{
int this_value;
va_list array;
va_start(array, arrayLen);
for (int i=0; i<arrayLen; i++)
{
this_value = va_arg(array, int);
printf("%i -> %i\n", i, this_value);
}
va_end(array);
}
I didn't compile this so I probably made a mistake or two, but hopefully it's close enough. Look up va_start for reference.
Here's a simple clean solution to get a C-style array that no-one else has mentioned:
#include <iostream>
using namespace std;
template <int N>
int
get_last( const int ( &my_array )[N] ) {
return my_array[N-1];
}
int main()
{
cout << "Last: " << get_last( { 1, 2, 3, 55 } );
return 0;
}
Another choice would be to use array in the TR1 library which is likely to become part of the next standard and is supported by many compilers.
#include <array>
#include <algorithm>
#include <iostream>
using std::tr1::array;
using std::cout;
using std::copy;
using std::ostream_iterator;
template <class Container>
void PrintArray(Container &values)
{
copy(values.begin(), values.end(), ostream_iterator<int>(cout, "\n"));
}
int main()
{
array<int, 5> values = {1, 2, 3, 4, 5};
PrintArray(values);
}
You can do this in ANSI-C using good ol' va_list
Templatized C++ with a std::vector returned for convenience in addition
#include <stdarg.h>
#include <vector>
using namespace std ;
struct Point
{
int x,y;
Point():x(0),y(0){}
Point( int ix, int iy ):x(ix),y(iy){}
~Point(){printf("%d %d - the point has been destroyed!\n",x,y);}
void print(){printf("%d,%d\n",x,y);}
} ;
// Concrete example using a list of int
int* initFrom( int numItems, ... )
{
int* list = new int[ numItems ] ;
va_list listPointer;
va_start( listPointer, numItems );
for( int i = 0 ; i < numItems; i++ )
list[ i ] = va_arg( listPointer, int ) ;
return list ;
}
// templatized version.
template <typename T> vector<T> initFrom( int numItems, ... )
{
vector<T> list ;
list.resize( numItems ) ;
va_list listPointer;
va_start( listPointer, numItems );
for( int i = 0 ; i < numItems; i++ )
list[ i ] = va_arg( listPointer, T ) ;
return list ;
}
int main()
{
int* theList = initFrom( 4, 900, 2000, 1000, 100 ) ;
for( int i = 0 ; i < 4 ; i++ )
printf( "Item %d=%d\n", i, theList[i] );
puts( "\n\n--Lots of destruction using non-ptr" ) ;
vector<Point> thePoints = initFrom<Point>( 3, Point(3,7), Point(4,5), Point(99,99) ) ;
puts( "Our listing:" ) ;
for( int i = 0 ; i < 3 ; i++ )
thePoints[i].print() ;
puts( "\n\n-- Less destruction using ptr" ) ;
// Be careful of extra copy construction. Using a vector of pointers
// will avoid that
vector<Point*> theNewPoints = initFrom<Point*>( 3, new Point(300,700), new Point(400,500), new Point(990,990) ) ;
puts( "Our listing:" ) ;
for( int i = 0 ; i < 3 ; i++ )
theNewPoints[i]->print() ;
puts( "END OF PROGRAM --" ) ;
}
PrintArray function is expecting a int*, but const. So you can pass a temporary int array created with new.
PrintArray(5, new int[5]{5,6,7,8,9});
Or with std::move() to add more sense.
#include <utility>
PrintArray(5, std::move(new int[5]{5,6,7,8,9}));
No, and it's bad coding practice anyway. Just declare const int* foo = {5,6,7,8,9}; before the function call. Even if this did work, it wouldn't speed up your program or compile time. The values would still need to be allocated in memory and passed through the function call.