9

I'm reading C++ Primer and in section 6.2 it says:

"Parameter initialization works the same way as variable initialization."

Yet when I do:

void foo(char* args[]) {return;}

int main() {

char* args[]={"asd","dsa"};  // ok.

foo({"asd","dsa"});          // error.

}

Why is that?

Shoe
  • 74,840
  • 36
  • 166
  • 272
4nt
  • 407
  • 2
  • 9
  • What does the error say? – tomi.lee.jones Jul 26 '15 at 23:31
  • 5
    books lie. often to make things simpler, sometimes because the author doesn't know better. – Cory Nelson Jul 26 '15 at 23:33
  • @CoryNelson to be fair, arrays are a bit of a corner case in C and C++. – Quentin Jul 26 '15 at 23:33
  • 5
    The *initialization* work in the same way. The *declaration*, however, doesn't. In particular, the function parameter `args`'s type is not an array. – T.C. Jul 26 '15 at 23:35
  • @T.C. I think you are right, since you can't pass an array to a function. It's just a **char. – 4nt Jul 26 '15 at 23:36
  • @CoryNelson it's pretty much true: parameters are copy-initialized from their argument. OP only got tripped up in this case because of the *adjustment* of array declarators in a parameter list (which happens before the parameter is initialized). – M.M Jul 27 '15 at 00:54

4 Answers4

4

As @T.C. pointed out in the comments, the args in the function argument is converted to a char** because functions can't take arrays as an argument. Since you can't do

char **asd={"asd","dsa"}; 

the code is illegal. My confusion came from the fact that

char* args[]={"asd","dsa"};
char **asd=args;

is legal.

4nt
  • 407
  • 2
  • 9
  • 1
    Related reading: http://stackoverflow.com/questions/22677415/why-do-c-and-c-compilers-allow-array-lengths-in-function-signatures-when-they – M.M Jul 27 '15 at 00:58
3

It is generally possible to take advantage of the new initialization syntax and semantics to use anonymous arrays as arguments, but you will have to jump through a few hoops. For example

typedef const char *CC2[2];

void foo(const CC2 &a) {}

int main() {
  foo({ "asd", "dsa" });
}

However, in your case this technique will not help because you are requesting an array-to-pointer conversion on a temporary array. This is illegal in C++.

typedef int A[2];

const A &r = A{ 1, 2 }; // reference binding is OK
int *p = A{ 1, 2 };     // ERROR: taking address is not OK

So, if you really want to do something like this, you can do the following

template <size_t N> void foo(const char *const (&args)[N]) {}

int main() {
  foo({ "asd", "dsa" });
}

but that is not exactly what you had in mind originally.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
0

Why is that?

First of all in both cases, you need char const* because you are working with string literals.

Secondly, {...} could work if the parameter type was an array, but char*[] is adjusted to char** (due to decayment) which cannot be initialised with a braced-init-list.


Alternatively use std::string and std::vector, as you are already supposed to do:

void foo(std::vector<std::string> args) {return;}

and:

foo({"asd","dsa"});

will work just fine.

Shoe
  • 74,840
  • 36
  • 166
  • 272
  • You're saying `{...}` is deduced to a `std::initializer_list` when that is never the case when initializing non-class types (and not deducing from `auto`). And no, the parameter type is not `T[]`. The declaration is *adjusted* to `T*` and the argument (if an array) will be implicitly converted. – David G Jul 26 '15 at 23:41
  • I'm using Visual C++ 2010 and it doesn't include initializer_list. – 4nt Jul 26 '15 at 23:41
0

"Parameter initialization works the same way as variable initialization."

This is true as far as calling constructors, I think they mean. However, initializers are special, and different from ordinary value expressions you can assign to a variable or pass to a function call.

C/C++ doesn't have a way to write a literal anonymous array. You can only do it as an initializer as you declare a variable.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847