Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does the number of braces affect uniform initialization?

Consider the following code snippet:

#include <iostream>  struct A {   A() {}   A(const A&) {} };  struct B {   B(const A&) {} };  void f(const A&) { std::cout << "A" << std::endl; } void f(const B&) { std::cout << "B" << std::endl; }  int main() {   A a;   f(   {a}   ); // A   f(  {{a}}  ); // ambiguous   f( {{{a}}} ); // B   f({{{{a}}}}); // no matching function } 

Why does each call fabricate the corresponding output? How does the number of braces affect uniform initialization? And how does brace elision affect all this?

like image 551
user1494080 Avatar asked Feb 03 '19 15:02

user1494080


People also ask

What is uniform initialization?

Uniform Initialization in C++ The uniform initialization is a feature that permits the usage of a consistent syntax to initialize variables and objects which are ranging from primitive type to aggregates. In other words, it introduces brace-initialization that applies braces ({}) to enclose initializer values.

What is init CPP?

Initialization of a variable provides its initial value at the time of construction. The initial value may be provided in the initializer section of a declarator or a new expression. It also takes place during function calls: function parameters and the function return values are also initialized.


1 Answers

Overload resolution is fun like this.

  1. {a} has exact match rank for initializing (a temporary for) the const A& parameter, which outcompetes the user-defined conversion B(const A&) as a realization of {a}. This rule was added in C++14 to resolve ambiguities in list-initialization (along with adjustments for aggregates).

    Note that the notional temporary is never created: after overload resolution picks f(const A&), the reference is simply initialized to refer to a, and this interpretation can apply even for non-copyable types.

  2. It would be permissible to initialize a const A& parameter (as above) to the constructor for either A or B, so the call is ambiguous.
  3. Calling a copy constructor (here, A(const A&)) repeatedly is prohibited as multiple user-defined conversions—rather than allowing one such conversion per level of overload resolution. So the outermost braces must initialize a B from the A initialized from {{a}} as (permitted) in the second case. (The middle layer of braces could initialize a B, but copying it with the outer layer would be prohibited and there’s nothing else to try to initialize.)
  4. Every interpretation involves such a disallowed extra conversion.

No brace elision is involved—we don’t know the outermost target type to allow it.

like image 78
Davis Herring Avatar answered Sep 26 '22 00:09

Davis Herring