Array size metafunction - is it in boost somewhere? - c++

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?

Related

Force gsl::as_span to return a gsl::span<const T>?

Given the following function, taking: a read-only float span (of either dynamic or any static size):
template <long N> void foobar(gsl::span<const float, N> x);
Let's say I have a vector<float>. Passing that as an argument doesn't work, but neither does using gsl::as_span:
std::vector<float> v = {1, 2, 3};
foobar(gsl::as_span(v));
The above does not compile. Apparently gsl::as_span() returns a gsl::span<float>. Besides not understanding why implicit cast to gsl::span<const float> isn't possible, is there a way to force gsl::as_span() to return a read-only span?
Poking around GSL/span.h on the github page you linked to, I found the following overload of as_span that I believe is the one being called here:
template <typename Cont>
constexpr auto as_span(Cont& arr) -> std::enable_if_t<
!details::is_span<std::decay_t<Cont>>::value,
span<std::remove_reference_t<decltype(arr.size(), *arr.data())>, dynamic_range>>
{
Expects(arr.size() < PTRDIFF_MAX);
return {arr.data(), narrow_cast<std::ptrdiff_t>(arr.size())};
}
There's lots to digest here, but in particular the return type of this function boils down to span<std::remove_reference<decltype(*arr.data())>, ...>. For your given vector<float> gives span<float,...> because decltype(*arr.data()) is float &. I believe the following should work:
const auto & cv = v;
foobar(as_span(cv));
but can't test it myself unfortunately. Let me know if this works.
as_span is not part of MS/GSL any more, probably because gsl::span was lately aligned to std::span - which you could now use with C++20.
You can use std::as_const to get a const container and create a gsl::span from that (or in your case to use gsl::as_span on it).
foobar(gsl::span<const float>(std::as_const(v)));
Please note that depending on the implementation of foobar it is not necessary to template it. You could also just write
void foobar(gsl::span<const float> x);
Per default the length of the span is dynamic_extent, so spans of any length would be accepted. Of course you would not have the length available during compile time.

Creating std::vector from list of arguments using Templates

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++)

Check sizes are the same when compiling

I have a dictionary and an array neither of which change size during the program but could often be extended pre compilation. The number of keys and the array length should always be the same size. Is there a way to check this when compiling as it'd be easy to add the key but not to the array or visa versa?
There are ways to check compile time constants. In C++11 it has been cemented with static_assert but it's possible with templates as well.
For example given:
enum Key {
K_Zero,
K_One,
K_Two,
K_NUMBER_ELEMENTS
};
static char const Dictionary[] = { ... };
You would do it C++11:
static_assert(K_NUMBER_ELEMENTS == ARRAY_SIZE(Dictionary),
"Keys / Dictionary mismatch");
Where ARRAY_SIZE is defined as:
template <typename T, unsigned N>
char (&ComputeArraySize(T (&)[N]))[N];
#define ARRAY_SIZE(Array) sizeof(ComputeArraySize(Array))
If you are still in C++03 (which is probably the case if you don't know the version), then you ought to be a little more clever and replace the static_assert with:
template <unsigned M, unsigned N> struct mp_equal;
template <unsigned N> struct mp_equal<N,N> {};
namespace {
mp_equal<K_NUMBER_ELEMENTS, ARRAY_SIZE(Dictionary)>
AssertKeysAndDictionarySizeMatch = {};
}
Which will trigger a compile time error if they do not match.
Assuming by dictionary you mean map or unordered_map there's no immediate way to do it at compile time. You could runtime assert in main OR you could force the map to be always initialized from an array of pairs, and then static_assert that the length of the pair array is the same as your main array.

Size-Of C-Array as a function? [duplicate]

This question already has an answer here:
Closed 11 years ago.
Possible Duplicate:
How does this “size of array” template function work?
Is there any possibility to implement NARR without a macro in C++ (C++0x)?
const static pair<string,int> data[] = {
{"Montag",1}, {"Dienstag",2}, {"Mittwoch",3}, {"Donnerstag",4},
{"Freitag",5}, {"Samstag",6}, {"Sonntag",7}
};
#define NARR(A) (sizeof(A)/sizeof(*A))
const static map<string,int> german_weekdays(data, data+NARR(data));
A simple function is not possible, because then the [] loses its size-information and becomes just another poiner:
size_t narr(sometype arr[]) { /* won't work */ }
Templates? Overloading? Magic?
It is possible in C++:
template< typename T, std::size_t Size >
std::size_t size(const T (&)[Size])
{
return Size;
}
The advantage of this over the macro solution is that the compiler will cough up a nasty error message if you try to pass a pointer to this.
In C++0x:
#include <iterator>
const static map<string,int> german_weekdays(data, std::end(data));
Also you can use std::begin(data) if you like, for symmetry or genericness[*]. And possibly you can use an initializer list instead of an array anyway...
[*] Although for full genericness, you should probably do:
using std::begin;
using std::end;
begin(data), end(data);
The reason is that the new "range-based for loop" syntax is equivalent to using begin and end without qualification, but with std as an associated namespace for ADL. So as with std::swap, authors of types might provide begin and end functions that are intended to be found via ADL. They probably ought to provide begin() and end() member functions instead, which std::begin and std::end will call. But if they provide something that works with ranged-based for, and doesn't work with your code, then you'll have to have an argument who should change.
I can't test this right now, because I've been away for a while and the latest GCC 4.6 just refused to compile, but constexpr should make short work of the question. Of course, it's better to sidestep this issue using Steve's suggestion.
template< typename T, size_t N >
constexpr size_t narr( T const (&)[ N ] )
{ return N; }

How to initialize all elements in an array to the same number in C++ [duplicate]

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;