Uniform Initialization inside constructor/function declaration parameter list
Asked Answered
F

1

6

I am learning some basic things about classes and OOP in C++. From what I read the preferred modern way of initializing a variable is to use uniform initialization.

In the simple class header example below, uniform initialization is used to initialize the 3 data members (length, width and height).

For consistency, I thought it might be a good idea to use uniform initialization when setting default values in the constructor declaration but this does not work and the compiler (gcc 6.3 on Debian Stretch) generates and error. From what I can see the compiler thinks the curly braces {} are the start of the constructor definition body (clearly it is not since the right bracket ")" has not yet been added).

I accept this will not work but out of curiosity is there a reason why? I would prefer to be consistent with my code and use uniform initialization where ever possible.

Thanks.

#ifndef BOX_H
#define BOX_H

class Box
{

private:
    double length {1.0};
    double width {1.0};
    double height {1.0};

public:
    //constructor
    Box(double l = 1.0, double w = 1.0, double h = 1.0); //ok
    //Box(double l {1.0}, double w {1.0}, double h {1.0}); //Error

    double volume();
};

#endif

EDIT....thanks for the comments so far but I'm not sure I understand the reason why you cannot use uniform initialization for default arguments. Is there some standard C++ documentation someone can point me to?

For example, taking the basic program below, it is ok to initialize n with a value of 5 using uniform initialization but it is not ok to initialize x like this as a default argument in the function header (I am using gcc 6.3 with -std=c++17). Why is this? Apologies if I have not understood the help so far.

#include <iostream>

void printNum(int x {1}) //error
{
    std::cout<<x<<"\n";
}

int main()
{
    int n {5};  //OK

    printNum(n);
}
Fenland answered 14/10, 2018 at 18:36 Comment(6)
A default value still needs the assignment, no matter what.Verily
Once you get past your error, This may help with initialization.Finer
Post updated with a basic example. The code in the "duplicate" post seems to be marked as valid but the code in my post does not seem to be valid and I'd like to understand why this is so or if there is some background design reason as to why this is not valid C++ syntax.Fenland
The “duplicate” doesn’t really answer this question.Alkane
Because providing default value is not about initialization, but parameter passing?Bryan
Thanks Jean-Baptiste....thinking about it from that angle does kind of make sense.Fenland
B
6

It's a grammatical constraint. This specific grammar element is described in [dcl.fct] ¶3:

parameter-declaration-clause:
  parameter-declaration-listopt ...opt
  parameter-declaration-list , ...

parameter-declaration-list:   
  parameter-declaration
  parameter-declaration-list , parameter-declaration

parameter-declaration:    
  attribute-specifier-seqopt decl-specifier-seq declarator 
  attribute-specifier-seqopt decl-specifier-seq declarator = initializer-clause
  attribute-specifier-seqopt decl-specifier-seq abstract-declaratoropt
  attribute-specifier-seqopt decl-specifier-seq abstract-declaratoropt = initializer-clause

The thing to note is that the grammar permits an initializer-clause to be present only if it's preceded by a =. I suspect it's to ensure there's no ambiguity between function declarations and object declarations. For instance, in block scope:

Widget foo(CompA{}, CompB{});

Has to be an object declaration, like the uniform initialization proposal wanted to make sure. Allowing plain {} as a default argument would make the above ambiguous, and we'll just have another vexing parse to add to the collection. So a = is required.

Now, as for why not allow it in a constructor where ambiguity is unlikely: the standard committee is not really in the habit of allowing a very constrained use-case if the more general one cannot be supported.

Bertrand answered 15/10, 2018 at 8:42 Comment(2)
Thanks StoryTeller.....that explanation certainly helps to settle the matter in my mind. Thank you for pointing to a specific example to clarify your point.Fenland
"we'll just have another vexing parse" we already have so many, nobody will notice :PBroadbent

© 2022 - 2024 — McMap. All rights reserved.