How to declare array with auto
TL;DR
template<typename T, int N> using raw_array = T[N];
auto &&z = raw_array<int,5>{};
Your example of auto z = int[5];
isn't legal any more than auto z = int;
is, simply because a type is not a valid initializer. You can write: auto z = int{};
because int{}
is a valid initializer.
Once one realizes this, the next attempt would be:
auto z = int[5]{};
Note that your int y[5]
does not have any initializer. If it had then you would have jumped straight here.
Unfortunately this does not work either for obscure syntax reasons. Instead you must find a legal way to name the array type in an initializer. For example, a typedef name can be used in an initializer. A handy reusable template type alias eliminates the burdensome requirement of a new typedef for every array type:
template<typename T, int N> using raw_array = T[N];
auto z = raw_array<int,5>{};
Aside: You can use template type aliases to fix the weird 'inside-out' syntax of C++, allowing you to name any compound type in an orderly, left-to-right fashion, by using this proposal.
Unfortunately due to the design bug in C and C++ which causes array-to-pointer conversions at the drop of a hat, the deduced type of the variable z
is int*
rather int[5]
. The resulting variable becomes a dangling pointer when the temporary array is destroyed.
C++14 introduces decltype(auto)
which uses different type deduction rules, correctly deducing an array type:
decltype(auto) z = raw_array<int,5>{};
But now we run into another design bug with arrays; they do not behave as proper objects. You can't assign, copy construct, do pass by value, etc., with arrays. The above code is like saying:
int g[5] = {};
int h[5] = g;
By all rights this should work, but unfortunately built-in arrays behave bizarrely in C and C++. In our case, the specific problem is that arrays are not allowed to have just any kind of initializer; they are strictly limited to using initializer lists. An array temporary, initialized by an initializer list, is not itself an initializer list.
Answer 1:
At this point Johannes Schaub makes the excellent suggestion that we can use temporary lifetime extension.
auto &&z = raw_array<int,5>{};
decltype(auto)
isn't needed because the addition of &&
changes the deduced type, so Johannes Schaub's suggestion works in C++11. This also avoids the limitation on array initializers because we're initializing a reference instead of an array.
If you want the array to deduce its length from an initializer, you can use an incomplete array type:
template<typename T> using unsized_raw_array = T[];
auto &&z = unsized_raw_array<int>{1, 2, 3};
Although the above does what you want you may prefer to avoid raw arrays entirely, due to the fact that raw arrays do not behave like proper C++ objects, and the obscurity of their behavior and the techniques used above.
Answer 2:
The std::array
template in C++11 does act like a proper object, including assignment, being passable by value, etc., and just generally behaving sanely and consistently where built-in arrays do not.
auto z = std::array<int,5>{};
However, with this you miss out on being able to have the array type infer its own length from an initializer. Instead You can write a make_array
template function that does the inference. Here's a really simple version I haven't tested and which doesn't do things you might want, such as verify that all the arguments are the same type, or let you explicitly specify the type.
template<typename... T>
std::array<typename std::common_type<T...>::type, sizeof...(T)>
make_array(T &&...t) {
return {std::forward<T>(t)...};
}
auto z = make_array(1,2,3,4,5);
Why can't I create an array of automatic variables?
auto
deduces every brace-enclosed initializer list to a std::initializer_list<T>
. (See §7.1.6.4.6 including the example).
Unfortunately you cannot initialize an array or even std::array
from a std::initializer_list
once you have obtained it, but you can use a std::vector
.
#include <vector>
#include <array>
#include <initializer_list>
int main()
{
auto x = {1,2,3};
std::array<int, 3> foo1 = x; // won't work for whatever reason
std::vector<int> foo2 = x; // works as expected
return 0;
}
Of course this defeats the whole purpose of what you are trying to do.
I tried writing a work around called make_array
but had to realize that this cannot ever work as the size of an initializer_list
isn't part of its template arguments and so you only instantiate one make_array
template for each T
. This sucks.
template<typename T>
auto make_array(const std::initializer_list<T>& x)
-> std::array<T, x.size()> { } // maaah
Well, apparently you can go for the variadic-template hack mentioned here How do I initialize a member array with an initializer_list?
(C++14) Array of lambdas: error: 'name' declared as array of 'auto'
The C++ language forbids having arrays declared with auto
. You have two good options: function pointers and even better - std::function
. Something like this:
std::function<bool(const Vector3&, const Vector3&)> selectionFuncs[8] =
{
[&](const Vector3& min, const Vector3& max)
{
return max.x_ == seamValues.x_ || max.y_ == seamValues.y_ || max.z_ == seamValues.z_;
},
[&](const Vector3& min, const Vector3& max)
{
return min.x_ == seamValues.x_;
},
// ...
};
Don't forget to #include <functional>
. Then you just use the elements of the array like any other functions.
How to auto create arrays
- Read the first line and convert the result to a number that you store to
count
. - Then add this line:
int [] array = new int [count];
- Next setup a
for
loop:for( var i = 0; i < count; ++i )
and in this loop, you read the current line, convert the value to a number and store it toarray [i]
.
Is this explanation simple enough?
For the concrete Java code, you should use your own brain, otherwise it will never change that you don't understand …
If this "100 entries" limit is relevant, you create a list of arrays (List<int[]> arrays
) and the sequence of code looks a bit different:
- Get the amount of numbers in the file.
- Setup a
while
loop:while( count > 100 )
. - In that loop, you create an array for 100 values and store it to the list:
Further you read the next 100 lines, convert the values to numbers and store them toint [] array = new int [100];
arrays.add( array );array [i]
; for that, you use afor
loop as above. - The last operation in the
while
loop is this:count -= 100;
. - After the
while
loop, you add the code from above the separator line, with one addition: after creating the array, you need to add it to the list of arrays before you start thefor
loop.
Access auto declared array
Which possibilities exist to access a single value explicitly of this array?
It's not an array, but is deduced to a std::initializer_list<double>
which can be accessed through an iterator or a range based loop:
#include <iostream>
auto messwerte2 = { 3.5, 7.3, 4.9, 8.3, 4.4, 5.3, 3.8, 7.5 };
int main() {
for(auto x : messwerte2) {
std::cout << x << std::endl;
}
}
Live Demo
To make it an array use an explicit array declaration:
double messwerte2[] = { 3.5, 7.3, 4.9, 8.3, 4.4, 5.3, 3.8, 7.5 };
How to initialize auto-type array of multiple types objects
You need a tuple instead of an array. However then you can't use a for loop but you have to exploit compile-time methods as the fold expression in the code below:
#include <tuple>
#include <iostream>
using namespace std;
struct gray_pixel {
uint8_t gray;
auto intensity() const {
return gray - 127;
}
};
struct rgb_pixel{
float red, green, blue;
auto intensity() const {
return (red - 127 + green -127 + blue - 127) * 255 / 3;
}
};
template<typename T>
auto intensity(const T& pixel){
return pixel.intensity();
}
//find the average intensity of multiple pixels from different types (gray_pixel or rgb_pixel)
template <typename... Ts>
auto average_intensity(Ts&&... args)
{
// you actually don't need this here, but I leave it
// to clarify how to capture the args in a tuple.
// you can use std::apply to perform calculations on the elements
auto tup = std::forward_as_tuple(std::forward<Ts>(args)...);
const float count = sizeof...(Ts);
// a lambda that gets the intensity of a single pixel
auto get_intensity = [](auto&& pix) {
return static_cast<float>(std::forward<decltype(pix)>(pix).intensity());
};
// fold expression to sum all the intensities of the args
auto sum = (get_intensity(args) + ...);
return sum/count;
}
int main()
{
gray_pixel pixel_gray = {255};
rgb_pixel pixel_rgb = {255,127,127};
cout << "sizeof(pixel_gray): " << sizeof(pixel_gray) << endl;
cout << "sizeof(pixel_rgb): " << sizeof(pixel_rgb) << endl;
cout << "intensity(pixel_gray): " << intensity(pixel_gray) << endl;
cout << "intensity(pixel_rgb): " << intensity(pixel_rgb) << endl;
cout << "average_intensity(pixel_gray, pixel_rgb): " << average_intensity(pixel_gray, pixel_rgb) << endl;
return 0;
}
This was the answer to the original question:
You could try it like this:
If all of your Ts
are of the same type, you can drop the std::common_type
and use the type of the first element instead.
Also I'd suggest to use std::array
instead of a C-style array.
#include <utility>
#include <array>
template<typename... Ts>
auto average_intensity(Ts&&... ts) {
using Auto = std::common_type_t <std::decay_t<Ts>...>;
std::array<Auto, sizeof...(Ts)> pixels {std::forward<Ts>(ts)...};
// or if you really want an C-style array
Auto pixels[]{std::forward<Ts>(ts)...};
}
Auto Rvalue Reference (without &&) to an Array in C++14
Clang is correct; see [conv.array]:
An lvalue or rvalue of type “array of
N
T
” or “array of unknown bound ofT
” can be converted to a prvalue
of type “pointer toT
”. The result is a pointer to the first element of the array.
Even if the array is a temporary, and therefore a prvalue, it is legal to perform the array-to-pointer conversion on it.
It appears that the restriction on converting array prvalues into pointers was introduced in a patch that resolved gcc bug 53220. It seems that a consensus emerged on the thread that allowing the conversion was dangerous since initializing a pointer variable from the array would not extend the lifetime of the array. However, treating such code as though it is ill-formed is not the correct solution, since, as pointed out later in the thread, it is possible to use this conversion in a safe way, e.g., if the array is being passed to a function that takes a pointer (and therefore will live until the function returns).
You would probably have to file a new bug against gcc in order to get them to fix the issue.
How to initialize all members of an array to the same value?
Unless that value is 0 (in which case you can omit some part of the initializer
and the corresponding elements will be initialized to 0), there's no easy way.
Don't overlook the obvious solution, though:
int myArray[10] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 };
Elements with missing values will be initialized to 0:
int myArray[10] = { 1, 2 }; // initialize to 1,2,0,0,0...
So this will initialize all elements to 0:
int myArray[10] = { 0 }; // all elements 0
In C++, an empty initialization list will also initialize every element to 0.
This is not allowed with C until C23:
int myArray[10] = {}; // all elements 0 in C++ and C23
Remember that objects with static storage duration will initialize to 0 if no
initializer is specified:
static int myArray[10]; // all elements 0
And that "0" doesn't necessarily mean "all-bits-zero", so using the above is
better and more portable than memset(). (Floating point values will be
initialized to +0, pointers to null value, etc.)
Related Topics
Why Gcc Does Not Use Load(Without Fence) and Store+Sfence for Sequential Consistency
Which Header Should I Include for 'Size_T'
Which Sorting Algorithm Is Used by Stl's List::Sort()
Global Variable "Count" Ambiguous
Std Linker Error with Apple Llvm 4.1
Getter and Setter, Pointers or References, and Good Syntax to Use in C++
How to Use C++ Modules in Clang
In C++ I Cannot Grasp Pointers and Classes
Getprocaddress Function in C++
Calculating Large Factorials in C++
How to Find the 'Temp' Directory in Linux
Is It Always the Case That Sizeof(T) >= Alignof(T) for All Object Types T
Should Accessors Return Values or Constant References
Best Practices for Use of C++ Header Files
How to Place a MACro in a Namespace in C++
Real-Time Pitch Detection Using Fft
How to Asynchronously Copy Memory from the Host to the Device Using Thrust and Cuda Streams