I have a lot of C# Code that I have to write in C++. I don't have much experience in C++.
I am using Visual Studio 2012 to build. The project is an Static Library in C++ (not in C++/CLI).
I am sorry if this has been answered already, but I just couldn't find it.
In the C# code they would initialize a lot of arrays like this:
C#
double[] myArray = {10, 20, 30, 40};
Looking at how they were using arrays, when copying the code to C++ I decided to use std::vector to replace them. I would like to be able to initialize the vectors in the same way, because in the Unit Tests they use the arrays initialisation heavily, but I can't. I think in further versions of c++, vector supports it, but not in the one I have.
(Update)To make my previous statement more clear:
This doesn't work in VS2012:
vector<double> myVector{10, 20, 30, 40};
From this question I learned to create a vector from an array, so now I have a function like this:
C++
template<typename T, size_t N>
static std::vector<T> GetVectorFromArray( const T (&array)[N] )
{
return std::vector<T>(array, array+N);
}
It works great, but now that means I have to create the array and then use my function:
C++ (I would like to avoid this, since the UnitTests have many arrays.)
double array[] = {1, 3, 5};
vector<double> myVector = ArrayUtils::GetVectorFromArray(array);
Is there a way I could make my function GetVectorFromArray receive a list of items, that I could later convert into a vector?
My compiler doesn't support C++11
You can't have "literal" arrays except when initializing an array in a declaration.
At least that was the case before C++11 standard, which allows things like what you want, but with an std::initializer_list argument:
template<typename T>
static std::vector<T> GetVectorFromArray( std::initializer_list<T> list )
{
return std::vector<T>(list);
}
On the other hand, if your compiler support C++11 you can use it directly with the std::vector instead:
std::vector<int> myVector = { 1, 3, 5 };
Or even (with uniform initialization)
std::vector<int> myVector{ 1, 3, 5 };
Note: Unfortunately VS2012 doesn't support these things, so you either to use temporary arrays, or upgrade to a compiler which support it (like VS2013, or GCC, or Clang).
There are alternatives. One of them is the Boost assignment library (as answered by Mark Tolonen).
You can also use old C-style variable arguments. See e.g. this old question and its accepted answer for tips on how to do that. For this to work, you either need to provide the number of elements in the argument list as the first function argument, or provide a special sentinel to mark the end of the list. A warning though: As this is inherited straight from C, the extra type-safety provided by C++ doesn't exist. If you give an argument of the wrong type (say a double or a char) you might get undefined behavior.
The only other solution is to emulate e.g. the Boost assignment library, but that will require ridiculous amounts of code for such a simple thing.
You can simulate this behavior using the third-party C++ library, Boost:
#include <boost/assign.hpp>
#include <vector>
#include <iostream>
int main()
{
std::vector<int> v = boost::assign::list_of(1)(2)(3)(4)(5);
for(auto i : v)
std::cout << i << std::endl;
}
You can also initialize a vector from an array using only the std library via non-member begin/end:
#include <boost/assign.hpp>
#include <vector>
#include <iostream>
int main()
{
int array[] = {1,2,3,4,5,6,7,8,9,10};
std::vector<int> v(std::begin(array),std::end(array));
for(auto i : v)
std::cout << i << std::endl;
}
Visual studio 2012 does not support initializer list. You could use VS 2013 for support (or g++)
Related
I am trying to create a std::vector from a boost::hana::tuple at compile-time like so:
boost::hana::tuple<std::string> namesString{ "Hello", "World" };
std::vector<std::string> namesStringVector{};
while(!(hana::is_empty(namesString)))
{
namesStringVector.emplace_back(hana::front(namesString));
hana::drop_front(namesString);
}
This clearly doesn't work because the while loop is not run at compile-time.
How do we achieve this effect in Boost::Hana? I.e. what compile-time Hana construct would allow us to perform this cast? I tried doing
namesStringVector = (std::vector<std::string>)namesString;
and
hana::to < std::vector < std::string > >(namesString);
But it tells me there does not exist such a cast in both cases.
In addition to the concerns that Louis addressed there are some other issues with how you are trying to use a tuple. Note that a tuple can not have its length or the types within it changed as types are completely immutable in C++ so you have to think in terms of pure functional programming.
Your call to is_empty will always return true, and drop_front can not change the input value, it only returns a new tuple with the front element removed. (in your case it would be tuple<> which is empty).
You might want to rethink your use case for wanting to convert a tuple to vector, but here is an example to hopefully get you started.
#include <boost/hana.hpp>
#include <iostream>
#include <string>
#include <vector>
namespace hana = boost::hana;
template <typename T>
constexpr auto to_vector = [](auto&& ...x) {
return std::vector<T>{std::forward<decltype(x)>(x)...};
};
int main() {
auto xs = hana::make_tuple("Hello", "World");
auto vec = hana::unpack(xs, to_vector<std::string>);
for (auto const& x : vec) {
std::cout << x << ' ';
}
std::cout << '\n';
}
Notes about list types:
std::vector has a run-time length and a single type for all
elements.
std::array has a compile-time length and a single type for all
elements.
hana::tuple has a compile-time length and any element can be any
type.
For starters, boost::hana::tuple<std::string> namesString{ "Hello", "World" }; doesn't make sense because your tuple only has one element but you try to initialize it with two.
Second, it doesn't really make sense to initialize a std::vector from a hana::tuple, since it implies that all the elements of the tuple have the same type. Instead, you should probably be using std::array. Hana is useful when you need heterogeneity (elements with different types), which you don't seem to need here. When you don't need heterogeneity, using std::array or similar tools will be much easier and natural than using Hana.
I am trying to use a pointer to an array inside of a for each loop in C++. The code below won't work because the "for each statement cannot operate on variables of type 'int *'". I'd prefer to use the new operator so that the array is on the heap and not the stack, but I just can't seem to figure out the syntax here. Any suggestions?
#include <iostream>
using namespace std;
int main() {
int total = 0;
int* array = new int[6];
array[0] = 10; array[1] = 20; array[2] = 30;
array[3] = 40; array[4] = 50; array[5] = 60;
for each(int i in array) {
total += i;
}
cout << total << endl;
}
That for each thing you are using is a Visual C++ extension that's not even recommended by some microsoft employees (I know I've heard STL say bad things about it, I can't remember where).
There are other options, like std::for_each, and range-based for from C++11 (though I don't think Visual C++ supports that yet). However, that's not what you should be using here. You should be using std::accumulate, because this is the job that it was made for:
total = std::accumulate(array, array + 6, 0);
If you're really just interested in how to use this Microsoft for each construct, well, I'm pretty sure you can't if you just have a pointer. You should use a std::vector instead. You should be doing that anyway.
C++0x introduced a ranged-based for loops, which work equal to foreach in other languages. The syntax for them is something like this:
int arr[5]={1,2,3,4,5};
for( int & tmp : arr )
{
//do something
}
These loops work for C-style arrays, initializer lists, and any type that has begin() and end() functions defined for it that return iterators.
I strongly believe that int * doesn't have begin() and end() functions for them that return iterators, because it's just a raw pointer. I also believe that other foreach-equivalents such as foreach in Qt, or what you've posted, work the same way, so you can't use them like this. msdn says that it works for collections:
for each (type identifier in expression) {
statements
}
expression:
A managed array expression or collection. The compiler must be able
to convert the collection element from Object to the identifier type.
expression evaluates to a type that implements IEnumerable, IEnumerable,
or a type that defines a GetEnumerator method. In the
latter case, GetEnumerator should either return a type that implements
IEnumerator or declares all the methods defined in IEnumerator.
Once again, you have a raw pointer, so it will not work.
you can always use for loop like this:
for (int i = 0; i < 6;i++)
{
total += array[i];
}
Although, answer for using "for each" using "gcnew" is already being given so I am omitting that. As an alternative, you can also use vectors as follows:
#include <iostream>
#include <vector>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
int total = 0;
vector<int> myarray;
myarray.push_back(10);
myarray.push_back(20);
myarray.push_back(30);
myarray.push_back(40);
myarray.push_back(50);
myarray.push_back(60);
for each(int i in myarray) {
total += i;
}
cout << total << endl;
return 0;
}
Hope this will help...
The only way I can think about is iterating over array of reference types especially if you want your storage on the heap
Here Microsoft shows you how to do so
But for your case, the simplest alternative (if you want your array on the heap) would be as follows:-
array<int>^ arr = gcnew array<int>{10, 20, 30, 40. 50, 60};
int total = 0;
for each (int i in arr){
total+=i;
}
gcnew creates an instance of a managed type (reference or value type) on the garbage collected heap. The result of the evaluation of a gcnew expression is a handle (^) to the type being created.
You have to use an standard library collection such as std::vector or std::arrayto use for each.
Please note that this codee I not standard C++, therefore not portable, because for each is a Visual C++ extension. I recommend to use std::for_each or C++11 auto ranged loops.
VC++ is not different from ISO/ANSI C++. Anybody who tells you that it is, is wrong. Now, to answer your question of the for each statement. There is no such statement in the ISO C++ specification. Microsoft supports the 'foreach' statement in C#, as part of the .Net framework. As a result, there might be a chance that this is supported in Visual Studio, although I would recommend not using it.
Like the user shubhansh answered a few replies back, try using a vector. However, I'm guessing you would like to use a generic size, rather than hard-coding it in. The following for loop would help you in this regard:
for(vector<int>::size_type i =0; i<myarray.size();i++)
{
total+=1;
}
This is the perfect way to iterate through a vector, as defined by the ISO standard.
Hope this helps you in your development.
Cheers!
I found the following template on a blog:
template <typename T, size_t N>
struct array_info<T[N]>
{
typedef T type;
enum { size = N };
};
It is an elegant alternative to sizeof(a) / sizeof(a[0]).
A commonly-used construct for getting the size of an array should surely be somewhere in a library. I'm not aware of one. Can anyone tell me this functionality is in the standard libraries somewhere and/or in Boost? Preferably in an easy-to-use and lightweight form.
I eventually found the answer myself - boost::size():
#include <boost/range.hpp>
int array[10];
boost::size(array); // returns 10
Although, these days you should probably use std::size() instead (since C++17)
In the new C++ standard, std::array from the header has the method size(), which returns a constexpr and is therefore available at compile time.
You should be able to to something like
std::array< YourType, N > arr;
constexpr auto totalSize = arr.size() * sizeof( std::array< YourType, N >::value_type );
Hope this helps...
C++ 17 support std::size() (defined in header <iterator>)
#include <iterator>
int my_array[10];
std::size(my_array);
std::vector<int> my_vector(10);
std::size(my_vector);
If possible, I would also recommend std::array or boost::array if possible. That said, you can also use boost::extent to obtain the array sizes, and boost::remove_all_extents to obtain the actual type.
In c++11, the type traits are also available in the standard library.
Edit: If your looking for a function that operates on variables, instead of types, try the following
template <typename T, std::size_t N>
std::size_t array_count(const T(&) [N]) { return N; }
See an example of use at http://ideone.com/IOdfp
You need perhaps the macro _countof. According to http://www.cplusplus.com/forum/beginner/54241/, it's #defined in <cstdio>. But I am not sure if it's available outside Visual C++.
Anyway, it's not complicated to create a header file and put your definition there.
Update:
_countof is Microsoft-specific, but there is a discussion about other compilers here: Equivalents to MSVC's _countof in other compilers?
For example, whats wrong with declaring the class doubler within the main function, if the predicate will only be used once?
#include <list>
#include <algorithm>
#define SIZE 10
int main()
{
std::list<int> myList;
for(int i=0; i<SIZE ;++i)
{
myList.push_back(i);
}
class doubler
{
public:
doubler(){}
int operator()(int a)
{
return a + a;
}
} pred;
std::for_each(myList.begin(), myList.end(), pred);
return 0;
}
The problem with this setup is that, at least in C++03, you cannot use a local functor as a template argument because it doesn't have external linkage. This means that technically speaking, the above code isn't legal. However, they're fixing this in C++0x since it's a pretty silly restriction, and since VS2010 has rudimentary C++0x support the above code is totally fine.
In short, the answer to your question is that there's nothing wrong with it if you're using C++0x-compliant compilers, but otherwise you should probably refrain from doing so to maximize cross-compiler compatibility.
It is illegal before C++0x
In C++0x, there is a better solution (lambdas/closures)
So in either case you should use a different solution.
This question already has answers here:
Initialization of all elements of an array to one default value in C++?
(12 answers)
Closed 4 months ago.
I'm trying to initialize an int array with everything set at -1.
I tried the following, but it doesn't work. It only sets the first value at -1.
int directory[100] = {-1};
Why doesn't it work right?
I'm surprised at all the answers suggesting vector. They aren't even the same thing!
Use std::fill, from <algorithm>:
int directory[100];
std::fill(directory, directory + 100, -1);
Not concerned with the question directly, but you might want a nice helper function when it comes to arrays:
template <typename T, size_t N>
T* end(T (&pX)[N])
{
return pX + N;
}
Giving:
int directory[100];
std::fill(directory, end(directory), -1);
So you don't need to list the size twice.
I would suggest using std::array. For three reasons:
1. array provides runtime safety against index-out-of-bound in subscripting (i.e. operator[]) operations,
2. array automatically carries the size without requiring to pass it separately
3. And most importantly, array provides the fill() method that is required for
this problem
#include <array>
#include <assert.h>
typedef std::array< int, 100 > DirectoryArray;
void test_fill( DirectoryArray const & x, int expected_value ) {
for( size_t i = 0; i < x.size(); ++i ) {
assert( x[ i ] == expected_value );
}
}
int main() {
DirectoryArray directory;
directory.fill( -1 );
test_fill( directory, -1 );
return 0;
}
Using array requires use of "-std=c++0x" for compiling (applies to the above code).
If that is not available or if that is not an option, then the other options like std::fill() (as suggested by GMan) or hand coding the a fill() method may be opted.
If you had a smaller number of elements you could specify them one after the other. Array initialization works by specifying each element, not by specifying a single value that applies for each element.
int x[3] = {-1, -1, -1 };
You could also use a vector and use the constructor to initialize all of the values. You can later access the raw array buffer by specifying &v.front()
std::vector directory(100, -1);
There is a C way to do it also using memset or various other similar functions. memset works for each char in your specified buffer though so it will work fine for values like 0 but may not work depending on how negative numbers are stored for -1.
You can also use STL to initialize your array by using fill_n. For a general purpose action to each element you could use for_each.
fill_n(directory, 100, -1);
Or if you really want you can go the lame way, you can do a for loop with 100 iterations and doing directory[i] = -1;
If you really need arrays, you can use boosts array class. It's assign member does the job:
boost::array<int,N> array; // boost arrays are of fixed size!
array.assign(-1);
It does work right. Your expectation of the initialiser is incorrect. If you really wish to take this approach, you'll need 100 comma-separated -1s in the initialiser. But then what happens when you increase the size of the array?
use vector of int instead a array.
vector<int> directory(100,-1); // 100 ints with value 1
It is working right. That's how list initializers work.
I believe 6.7.8.10 of the C99 standard covers this:
If an object that has automatic
storage duration is not initialized
explicitly, its value is
indeterminate. If an object that has
static storage duration is not
initialized explicitly, then:
if it has pointer type, it is initialized to a null pointer;
if it has arithmetic type, it is initialized to (positive or unsigned)
zero;
if it is an aggregate, every member is initialized (recursively) according
to these rules;
if it is a union, the first named member is initialized (recursively)
according to these rules.
If you need to make all the elements in an array the same non-zero value, you'll have to use a loop or memset.
Also note that, unless you really know what you're doing, vectors are preferred over arrays in C++:
Here's what you need to realize about containers vs. arrays:
Container classes make programmers more productive. So if you insist on using arrays while those around are willing to use container classes, you'll probably be less productive than they are (even if you're smarter and more experienced than they are!).
Container classes let programmers write more robust code. So if you insist on using arrays while those around are willing to use container classes, your code will probably have more bugs than their code (even if you're smarter and more experienced).
And if you're so smart and so experienced that you can use arrays as fast and as safe as they can use container classes, someone else will probably end up maintaining your code and they'll probably introduce bugs. Or worse, you'll be the only one who can maintain your code so management will yank you from development and move you into a full-time maintenance role — just what you always wanted!
There's a lot more to the linked question; give it a read.
u simply use for loop as done below:-
for (int i=0; i<100; i++)
{
a[i]= -1;
}
as a result as u want u can get
A[100]={-1,-1,-1..........(100 times)}
I had the same question and I found how to do, the documentation give the following example :
std::array<int, 3> a1{ {1, 2, 3} }; // double-braces required in C++11 (not in C++14)
So I just tried :
std::array<int, 3> a1{ {1} }; // double-braces required in C++11 (not in C++14)
And it works all elements have 1 as value. It does not work with the = operator. It is maybe a C++11 issue.
Can't do what you're trying to do with a raw array (unless you explicitly list out all 100 -1s in the initializer list), you can do it with a vector:
vector<int> directory(100, -1);
Additionally, you can create the array and set the values to -1 using one of the other methods mentioned.
Just use this loop.
for(int i =0 ; i < 100 ; i++) directory[i] =0;
the almighty memset() will do the job for array and std containers in C/C++/C++11/C++14
The reason that int directory[100] = {-1} doesn't work is because of what happens with array initialization.
All array elements that are not initialized explicitly are initialized implicitly the same way as objects that have static storage duration.
ints which are implicitly initialized are:
initialized to unsigned zero
All array elements that are not initialized explicitly are initialized implicitly the same way as objects that have static storage duration.
C++11 introduced begin and end which are specialized for arrays!
This means that given an array (not just a pointer), like your directory you can use fill as has been suggested in several answers:
fill(begin(directory), end(directory), -1)
Let's say that you write code like this, but then decide to reuse the functionality after having forgotten how you implemented it, but you decided to change the size of directory to 60. If you'd written code using begin and end then you're done.
If on the other hand you'd done this: fill(directory, directory + 100, -1) then you'd better remember to change that 100 to a 60 as well or you'll get undefined behavior.
If you are allowed to use std::array, you can do the following:
#include <iostream>
#include <algorithm>
#include <array>
using namespace std;
template <class Elem, Elem pattern, size_t S, size_t L>
struct S_internal {
template <Elem... values>
static array<Elem, S> init_array() {
return S_internal<Elem, pattern, S, L - 1>::init_array<values..., pattern>();
}
};
template <class Elem, Elem pattern, size_t S>
struct S_internal<Elem, pattern, S, 0> {
template <Elem... values>
static array<Elem, S> init_array() {
static_assert(S == sizeof...(values), "");
return array<Elem, S> {{values...}};
}
};
template <class Elem, Elem pattern, size_t S>
struct init_array
{
static array<Elem, S> get() {
return S_internal<Elem, pattern, S, S>::init_array<>();
}
};
void main()
{
array<int, 5> ss = init_array<int, 77, 5>::get();
copy(cbegin(ss), cend(ss), ostream_iterator<int>(cout, " "));
}
The output is:
77 77 77 77 77
Just use the fill_n() method.
Example
int n;
cin>>n;
int arr[n];
int value = 9;
fill_n(arr, n, value); // 9 9 9 9 9...
Learn More about fill_n()
or
you can use the fill() method.
Example
int n;
cin>>n;
int arr[n];
int value = 9;
fill(arr, arr+n, value); // 9 9 9 9 9...
Learn More about fill() method.
Note: Both these methods are available in algorithm library (#include<algorithm>). Don't forget to include it.
Starting with C++11 you could also use a range based loop:
int directory[10];
for (auto& value: directory) value = -1;