4

Now I have a function in C++

void F( std::array<int,3> x )
{
    //...
}

I hope the argument 'x' could have a default value, how can I do this?

If not a function argument, I can simply use

std::array<int,3> x = {1,2,3};

But for a function argument, the code

void F( std::array<int,3> x = {1,2,3} )
{
    //...
}

will make compiler error.


I test in MSVC 2012, and got error C2143, C2059, C2447. And also error in g++ 4.6.3


Is there any way make it has a default value?

thanks.

Heresy
  • 43
  • 3
  • What compiler error? Which compiler? (It might be a bug.. clang3.2 accepts your code; and I think your example complies to the Standard - it's aggregate-initialization) – dyp May 02 '13 at 11:20
  • I had add the comiple error. It looks that is my compiler not support this syntax yet... – Heresy May 02 '13 at 11:36
  • 1
    I found a stupid workaround...Use lambda expression. `void F( std::array x = [](){std::array x = {1,2,3}; return x; }() ){}` This works both on MSVC11 and G++ 4.6.3. – Heresy May 02 '13 at 12:24
  • It looks like this was not implemented yet in gcc 4.6.3, see [this SO question](http://stackoverflow.com/questions/6615823/uniform-initializer-used-in-default-argument-to-const-reference). Consider looking at [Microsoft Connect](http://connect.microsoft.com/VisualStudio) and file a bug report if it hasn't been detected yet. AFAIK, Morwenn's answer is wrong and this should be possible according to the Standard. – dyp May 02 '13 at 12:38
  • @DyP After reading again the standard, I think my answer is indeed wrong: he should be able to initialize the array the way he does. However, the work-around is not wrong: the standard says that braces *can* be elided, not that they *have to*. – Morwenn May 02 '13 at 13:40
  • @Morwenn Yes; you can chose not to elide braces. Considering the OP's question, your answer is correct, though the explanation why this works might be wrong. – dyp May 02 '13 at 14:06
  • @DyP I tried to changed it a little so that it is less wrong :p – Morwenn May 02 '13 at 14:08
  • @Morwenn Yeah, +1 now. Though this raises the question if we're wrong or both compilers have a bug o.O So either another SO question or two bug reports :( – dyp May 02 '13 at 14:12
  • @DyP I will let you ask that one if you wish. I'm not into asking anymore questions today. – Morwenn May 02 '13 at 16:43
  • The lambda expression workaround not work in MSVC2010... It said illegal use of local variable as default parameter.... I looks like I may only can use boost::array with boost::assign now. – Heresy May 03 '13 at 00:37

1 Answers1

11

Your solution should work according to the standard, but is not implemented in some compilers. Most of them can initialize instances of std::array with the syntax x = {{1,2,3}}, not with x = {1, 2, 3}. If you want it to work as of today, your function should be:

void F( std::array<int,3> x = {{1,2,3}} )
{
    //...
}

This is because std::array just has a C array underneath and initialize it with aggregate initialization. The first pair of braces are for the list initialization list while the second pair of braces is for the C-array initialization.

According to the standard (8.5.1.11), the outer braces can be elided in such a case if (and only if) you use the sign = for initialization. However, some compilers still do not support this behaviour (g++ being one of them).

And as a bonus, you can check it online with ideone.

Morwenn
  • 21,684
  • 12
  • 93
  • 152
  • Note that the standard is not totally clear about the implementation having an array data member, which can lead to confusion. – juanchopanza May 02 '13 at 10:17
  • 3
    I'm not entirely sure about this. The Standard says in [array.overview]/2 that an array is an aggregate that can be initialized like `std::array a = {1,2,3};`. There have to be two braces for direct-init, `std::array a{{1,2,3}};` – dyp May 02 '13 at 11:11
  • @Morwenn Thanks for your answer, but the code still get compile error in MSVC 2012. – Heresy May 02 '13 at 11:24
  • 3
    @Heresy Initializer-lists are not supported in MSVC 2012, see [SO question](http://stackoverflow.com/questions/7421825/c11-features-in-visual-studio-2012), [MSDN reference](http://msdn.microsoft.com/en-us/library/vstudio/hh567368.aspx) – dyp May 02 '13 at 11:36
  • @Heresy Maybe with the [November 2012 CTP version](http://blogs.msdn.com/b/vcblog/archive/2012/11/02/visual-c-c-11-and-the-future-of-c.aspx) – dyp May 02 '13 at 11:37
  • @DyP Thanks a lot. I forget check this first... I had install the update 2 of VS2012, still can't compile. Is there any way to do this in MSVC2012? I had tried Boost.Assign, but list_of not work wth std::array... (which works in gcc 4.6.3) – Heresy May 02 '13 at 11:44
  • @Heresy boost assign works with boost arrays, though. And as far as I understand the CTP, `array a = {1,2,3}` should also work. Maybe it's a bug. A simple solution would be to use boost arrays or to copy from another array `array def = {1,2,3}; void F(array x = def);` – dyp May 02 '13 at 11:56
  • [decl.init.aggr]/11: "If the initializer-list begins with a left brace, then the succeeding comma-separated list of initializer-clauses initializes the members of a subaggregate; it is erroneous for there to be more initializer-clauses than members." Therefore, IMHO this answer is wrong. Also see [this SO answer](http://stackoverflow.com/a/11735045/420683) and carefully read until the end. – dyp May 02 '13 at 13:09
  • @DyP Quite interesting. I remember having read that some time ago. However, I have had problems when trying to use brace elision with GCC. Could this be a GCC problem, then? – Morwenn May 02 '13 at 13:19
  • I think so. As a simple definition in main, `array a = {1,2,3};` even g++ 4.6 accepts it. But as a default argument, even g++ 4.8 refuses it. Though the Standard says: "The default argument has the same semantic constraints as the initializer in a declaration of a variable of the parameter type, using the copy-initialization semantics (8.5)." So maybe we've found a bug in both g++ 4.8 and MSVC November CTP? – dyp May 02 '13 at 14:04
  • @DyP As I think, there are no compiler complete support C++11 now. – Heresy May 02 '13 at 14:13
  • @Heresy clang 3.3 and gcc 4.8.1 IIRC - though they're not released yet – dyp May 02 '13 at 14:14