Passing array literal as function argument - c++

This code does not compile on VS2010:
struct Point {
float x;
float y;
};
void do_something(Point p) {
// something happens here
}
int main(int argc, char **argv) {
do_something({10, 11});
}
Are there any versions of C++ where this is legal syntax?

This looks like aggregate initialization to me. It should work in VS2013.
EDIT: Confirmed, this should work on a c++11 compiler.
Also, it isn't an array literal, it's aggregate initialization. You can find the rules on it here and here.
You might be able to download a newer compiler and run it on the older IDE, but short of that I don't think VS2010 can run this.

Related

Initialisation of array char in c++

Is the below method correct to initialize a char array? I have used this multiple times in my code and running that program in Visual Studio 2015 doesn't show any errors. Whereas when i compile the same program in Visual Studio 2012 i get a lot of errors, mostly with char array initialization.
So, my question is it okay to initialize that way? And is Visual Studio 2012 showing me a false error?
Any help would be highly appreciated!
char arr[10]={0};
In C++11 and onwards (which is broadly implemented by Visual Studio 2015 with very few omissions), you can go one stage further and write
char arr[10] = {};
This sets every element of arr to '\0'
I'd be tempted to drop compile support for VS2012 (which doesn't purport to implement the C++11 standard) if you are able to: the C++11 standard is an important leap forward in the development of C++. That said, char arr[10] = {0}; is valid C++03, your compile errors are due to other errors in you code.
In C++11
{}
is used for "Aggregate Initialization"
The aggregates are Arryas, Classes(structs) and unions. It takes out the tedious way of initializing arrays and classes which was the case prior to it. The empty Aggregate Initialization is used for Initializing everything with zero
for example
char arr[5] = {}
will initialize arr[0] to arr[4] with 0
struct s {
int i;
int j;
};
struct s s1 = {};
// make s1.i = s1.j = 0;
Aggregates can also be used for Initializing with values like
char str[] {"Test String"};
// This is equivalent to
char str[] = "Test String";
A simple integer or any other built in data type can also initialized like
int val { 123 };
// equivalent to
int val = 123;
Its also widely used in STL initialization. for example
std::array<int, 3> ay{ 1,2,3 };

clang++ cannot initialize a variable of type 'int(*)[dim2]' with an rvalue of type 'int (*)[dim2]'

Why does the code
void fcn(int *twoDArrayPtr, const int dim1, const int dim2) {
int (*array)[dim2] = reinterpret_cast<int (*)[dim2]>(twoDArrayPtr);
}
int main() {
return 0;
}
generate the compiler error
error: cannot initialize a variable of type 'int (*)[dim2]' with
an rvalue of type 'int (*)[dim2]'
The types are the same, so I'd think the assignment can be performed. Since int (*)[dim2] is a pointer to an array of size dim2 and as such could be a pointer to a bunch of arrays of size dim2 in contiguous memory indexable by the pointer, I would think this should work.
I'm using clang++ on Mac OS/X with the following version information:
Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin14.0.0
Thread model: posix
dim2 is not a compile-time constant, and VLAs (variable-length arrays) don't exist in C++. Some other compilers (such as gcc) have language extensions to allow VLAs in C++, but clang's behavior is standard-conforming.
You can work around the problem with a class (or class template) that does the address translation for you, such as
// This is very rudimentary, but it's a point to start.
template<typename T>
class array2d_ref {
public:
array2d_ref(T *p, std::size_t dim) : data_(p), dim_(dim) { }
T *operator[](std::size_t i) { return &data_[i * dim_]; }
private:
T *data_;
std::size_t dim_;
};
...
array2d_ref<int> array(twoDArrayPtr, dim2);
But I'm afraid it is not possible (portably) to have a pointer-to-array unless you know the dimension of the array at compile time.
You're trying to use C99's Variable Length Array(VLA) feature when you use dim2 as the array dimension in your cast. (gcc, for example does support this by extension: https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html.)
Good news, you can't do this now but you will be able to soon with the introduction of C++14's Runtime Sized Arrays.
Pertainant quotes:
Runtime-sized arrays offer the same syntax and performance of C99’s VLAs... Bear in mind that runtime-sized arrays aren’t precisely the same as C99’s VLAs. The C++14 feature is more restrained, which is just as well. Specifically, the following properties are excluded:
Runtime-sized multidimensional arrays
Modifications to the function declarator syntax
sizeof(a) being a runtime-evaluated expression returning the size of a
typedef int a[n]; evaluating n and passing it through the typedef
So you're code will be legal soon, circa C++14.
I've tried it out on the Visual Studio 2015 Beta and sadly at time of writing it is not supported :(
Although clang does not support variable-length arrays, there is a workaround. The following compiles with clang++ 4.0.0:
void fcn(int *twoDArrayPtr, const int dim1, const int dim2) {
using array_type = int (*)[dim2];
array_type array = reinterpret_cast<array_type>(twoDArrayPtr);
}
int main() {
return 0;
}
I'm not sure why this alias declaration should make any difference. It certainly seems inconsistent.

Ignoring GCC "error: braces around scalar initializer for type" errors. Make them warnings

I have a nagging problem with GCC compiler errors "error: braces around scalar initializer for type". I have seen others complaining about this, although they describe it as a warning (gcc warning: braces around scalar initializer)
I am compiling code which is not mine to edit, and I get a lot of these errors throughout the code.
Basic Pattern is:
struct t_
{
float f;
int i;
};
float f = { 0.3 }; //Compiler is all happy with this.
int i = {0}; //Compiler is all happy with this too.
t_ t1 = { 0.3, 0 }; //Compiler is all happy with this too.
t_ t2 = { {0.3}, 0 }; //Compiler ERROR: braces around scalar initializer for type 'float'
I know I can remove the braces {} around the float scaler to remove this error, but I do not want to modify the code in any way. Is there a flag I can give to GCC (currently using MinGW gcc 4.8.1). i.e. "std=c++03", or something to get these errors at least displayed as warnings.
Thanks
I'm not 100% sure, but I believe there is no such option. The construct you have is not meaning the same thing in the two cases - first one is an initialization of one structure, the second is a a strcuture containing a structure or array. Which of course float isn't.
You may be able to work around it with
struct t_
{
struct
{
float f;
};
int i;
};
At least clang is happy with that. As is g++. That may be easier than changing a lot of initialization statements with extra braces in them. But it is admittedly still a change to the source code. Unfortunately, I'm pretty certain that this is necessary.
Complete example that I was testing with:
struct t_
{
struct
{
float f;
};
int i;
};
t_ t2 = { {0.3}, 0 };
int main()
{
t2.f = 7;
}
Edit:
If it's not at all possible to edit the source, you'll need to parse the source code, identify the incorrect braces and output "correct" code. The more I think about this, the less I believe that it's at all possible to fix without some sort of edit to the source. Or that it has ever compiled...

"const variables" set by a constructor for expressing the bounds of a C++ array?

The following code compiles and it seems to run fine:
class Test {
private:
const unsigned MAX;
public:
Test (const unsigned int n) : MAX(n) { }
void foo () {
int array[MAX];
...
}
};
but is it really OK? I mean:
Test a (3);
Test b (8);
does array actually have 3 and 8 cells respectively?
If so, is it because array is an automatic var and gets instantiated with the appropriate dimension?
Thanks
What you have written is valid in c99 but not valid c++.
I am of course talking about your use of VLA's, not the full snippet.
When compiling using g++ -pedantic -ansi -Wall we get the below warning;
foo.cpp: In member function 'void Test::foo()':
foo.cpp:18:23: warning: ISO C++ forbids variable length array 'array' [-Wvla]
As mentioned in the above warning the pattern you are using is often referred to as using a variable length array, which is standard in C99 and "allowed" in C++ through a g++ extension.
I'd recommend you to use a STL container instead of hacks as these, for one single reason; what you are doing is not legal, and therefor isn't guaranteed to be portable cross compilers.
Variable length arrays are not standard C++. You could make Test a template instead:
template <int MAX>
class Test {
public:
Test () {}
void foo () {
int array[MAX];
}
};
Test<4> t4;
Test<8> t8;
You are correct that this is not legal C++. If it works on your compiler, it is probably because you are using a GCC extension.

Are flexible array members valid in C++?

In C99, you can declare a flexible array member of a struct as such:
struct blah
{
int foo[];
};
However, when someone here at work tried to compile some code using clang in C++, that syntax did not work. (It had been working with MSVC.) We had to convert it to:
struct blah
{
int foo[0];
};
Looking through the C++ standard, I found no reference to flexible member arrays at all; I always thought [0] was an invalid declaration, but apparently for a flexible member array it is valid. Are flexible member arrays actually valid in C++? If so, is the correct declaration [] or [0]?
C++ was first standardized in 1998, so it predates the addition of flexible array members to C (which was new in C99). There was a corrigendum to C++ in 2003, but that didn't add any relevant new features. The next revision of C++ (C++2b) is still under development, and it seems flexible array members still aren't added to it.
C++ doesn't support C99 flexible array members at the end of structures, either using an empty index notation or a 0 index notation (barring vendor-specific extensions):
struct blah
{
int count;
int foo[]; // not valid C++
};
struct blah
{
int count;
int foo[0]; // also not valid C++
};
As far as I know, C++0x will not add this, either.
However, if you size the array to 1 element:
struct blah
{
int count;
int foo[1];
};
the code will compile, and work quite well, but it is technically undefined behavior. You can allocate the appropriate memory with an expression that is unlikely to have off-by-one errors:
struct blah* p = (struct blah*) malloc( offsetof(struct blah, foo[desired_number_of_elements]);
if (p) {
p->count = desired_number_of_elements;
// initialize your p->foo[] array however appropriate - it has `count`
// elements (indexable from 0 to count-1)
}
So it's portable between C90, C99 and C++ and works just as well as C99's flexible array members.
Raymond Chen did a nice writeup about this: Why do some structures end with an array of size 1?
Note: In Raymond Chen's article, there's a typo/bug in an example initializing the 'flexible' array. It should read:
for (DWORD Index = 0; Index < NumberOfGroups; Index++) { // note: used '<' , not '='
TokenGroups->Groups[Index] = ...;
}
If you can restrict your application to only require a few known sizes, then you can effectively achieve a flexible array with a template.
template <typename BASE, typename T, unsigned SZ>
struct Flex : public BASE {
T flex_[SZ];
};
The second one will not contain elements but rather will point right after blah. So if you have a structure like this:
struct something
{
int a, b;
int c[0];
};
you can do things like this:
struct something *val = (struct something *)malloc(sizeof(struct something) + 5 * sizeof(int));
val->a = 1;
val->b = 2;
val->c[0] = 3;
In this case c will behave as an array with 5 ints but the data in the array will be after the something structure.
The product I'm working on uses this as a sized string:
struct String
{
unsigned int allocated;
unsigned int size;
char data[0];
};
Because of the supported architectures this will consume 8 bytes plus allocated.
Of course all this is C but g++ for example accepts it without a hitch.
If you only want
struct blah { int foo[]; };
then you don't need the struct at all an you can simply deal with a malloc'ed/new'ed int array.
If you have some members at the beginning:
struct blah { char a,b; /*int foo[]; //not valid in C++*/ };
then in C++, I suppose you could replace foo with a foo member function:
struct blah { alignas(int) char a,b;
int *foo(void) { return reinterpret_cast<int*>(&this[1]); } };
Example use:
#include <stdlib.h>
struct blah {
alignas(int) char a,b;
int *foo(void) { return reinterpret_cast<int*>(&this[1]); }
};
int main()
{
blah *b = (blah*)malloc(sizeof(blah)+10*sizeof(int));
if(!b) return 1;
b->foo()[1]=1;
}
A proposal is underway, and might make into some future C++ version.
See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1039r0.html for details (the proposal is fairly new, so it's subject to changes)
I faced the same problem to declare a flexible array member which can be used from C++ code. By looking through glibc headers I found that there are some usages of flexible array members, e.g. in struct inotify which is declared as follows (comments and some unrelated members omitted):
struct inotify_event
{
//Some members
char name __flexarr;
};
The __flexarr macro, in turn is defined as
/* Support for flexible arrays.
Headers that should use flexible arrays only if they're "real"
(e.g. only if they won't affect sizeof()) should test
#if __glibc_c99_flexarr_available. */
#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
# define __flexarr []
# define __glibc_c99_flexarr_available 1
#elif __GNUC_PREREQ (2,97)
/* GCC 2.97 supports C99 flexible array members as an extension,
even when in C89 mode or compiling C++ (any version). */
# define __flexarr []
# define __glibc_c99_flexarr_available 1
#elif defined __GNUC__
/* Pre-2.97 GCC did not support C99 flexible arrays but did have
an equivalent extension with slightly different notation. */
# define __flexarr [0]
# define __glibc_c99_flexarr_available 1
#else
/* Some other non-C99 compiler. Approximate with [1]. */
# define __flexarr [1]
# define __glibc_c99_flexarr_available 0
#endif
I'm not familar with MSVC compiler, but probably you'd have to add one more conditional macro depending on MSVC version.
Flexible arrays are not part of the C++ standard yet. That is why int foo[] or int foo[0] may not compile. While there is a proposal being discussed, it has not been accepted to the newest revision of C++ (C++2b) yet.
However, almost all modern compiler do support it via compiler extensions.
GCC has zero length array extension which is supported for C++.
Clang aims to supports a broad range of GCC extensions.
MSVC has a non standard extension and a warning associated with it.
The catch is that if you use this extension with the highest warning level (-Wall --pedantic), it may result into a warning.
A workaround to this is to use an array with one element and do access out of bounds. While this solution is UB by the spec (dcl.array and expr.add), most of the compilers will produce valid code and even clang -fsanitize=undefined is happy with it:
#include <new>
#include <type_traits>
struct A {
int a[1];
};
int main()
{
using storage_type = std::aligned_storage_t<1024, alignof(A)>;
static storage_type memory;
A *ptr_a = new (&memory) A;
ptr_a->a[2] = 42;
return ptr_a->a[2];
}
demo
Having all that said, if you want your code to be standard compliant and do not depend on any compiler extension, you will have to avoid using this feature.
Flexible array members are not supported in standard C++, however the clang documentation says.
"In addition to the language extensions listed here, Clang aims to support a broad range of GCC extensions."
The gcc documentation for C++ says.
"The GNU compiler provides these extensions to the C++ language (and you can also use most of the C language extensions in your C++ programs)."
And the gcc documentation for C documents support for arrays of zero length.
https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
The better solution is to declare it as a pointer:
struct blah
{
int* foo;
};
Or better yet, to declare it as a std::vector:
struct blah
{
std::vector<int> foo;
};