How does the number of braces affect uniform initialization?












21















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?










share|improve this question

























  • Completely attracted. But I think you' d better post your complier message. :)

    – Constructor
    yesterday











  • @Constructor the comments give the error messages when compiling with (at least) g++, else what is written during the execution

    – bruno
    yesterday








  • 3





    may want to add the tag language-lawyer

    – Eljay
    yesterday






  • 3





    Nit: semicolons after member function definitions are pointless and let the uninitiated imagine things like all closing braces should get one.

    – Davis Herring
    yesterday






  • 2





    @Rakete1111: There are more uses for null statements than null declarations (that are not also statements).

    – Davis Herring
    yesterday
















21















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?










share|improve this question

























  • Completely attracted. But I think you' d better post your complier message. :)

    – Constructor
    yesterday











  • @Constructor the comments give the error messages when compiling with (at least) g++, else what is written during the execution

    – bruno
    yesterday








  • 3





    may want to add the tag language-lawyer

    – Eljay
    yesterday






  • 3





    Nit: semicolons after member function definitions are pointless and let the uninitiated imagine things like all closing braces should get one.

    – Davis Herring
    yesterday






  • 2





    @Rakete1111: There are more uses for null statements than null declarations (that are not also statements).

    – Davis Herring
    yesterday














21












21








21


7






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?










share|improve this question
















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?







c++ c++11 language-lawyer uniform-initialization brace-initialization






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited yesterday







user1494080

















asked yesterday









user1494080user1494080

8002723




8002723













  • Completely attracted. But I think you' d better post your complier message. :)

    – Constructor
    yesterday











  • @Constructor the comments give the error messages when compiling with (at least) g++, else what is written during the execution

    – bruno
    yesterday








  • 3





    may want to add the tag language-lawyer

    – Eljay
    yesterday






  • 3





    Nit: semicolons after member function definitions are pointless and let the uninitiated imagine things like all closing braces should get one.

    – Davis Herring
    yesterday






  • 2





    @Rakete1111: There are more uses for null statements than null declarations (that are not also statements).

    – Davis Herring
    yesterday



















  • Completely attracted. But I think you' d better post your complier message. :)

    – Constructor
    yesterday











  • @Constructor the comments give the error messages when compiling with (at least) g++, else what is written during the execution

    – bruno
    yesterday








  • 3





    may want to add the tag language-lawyer

    – Eljay
    yesterday






  • 3





    Nit: semicolons after member function definitions are pointless and let the uninitiated imagine things like all closing braces should get one.

    – Davis Herring
    yesterday






  • 2





    @Rakete1111: There are more uses for null statements than null declarations (that are not also statements).

    – Davis Herring
    yesterday

















Completely attracted. But I think you' d better post your complier message. :)

– Constructor
yesterday





Completely attracted. But I think you' d better post your complier message. :)

– Constructor
yesterday













@Constructor the comments give the error messages when compiling with (at least) g++, else what is written during the execution

– bruno
yesterday







@Constructor the comments give the error messages when compiling with (at least) g++, else what is written during the execution

– bruno
yesterday






3




3





may want to add the tag language-lawyer

– Eljay
yesterday





may want to add the tag language-lawyer

– Eljay
yesterday




3




3





Nit: semicolons after member function definitions are pointless and let the uninitiated imagine things like all closing braces should get one.

– Davis Herring
yesterday





Nit: semicolons after member function definitions are pointless and let the uninitiated imagine things like all closing braces should get one.

– Davis Herring
yesterday




2




2





@Rakete1111: There are more uses for null statements than null declarations (that are not also statements).

– Davis Herring
yesterday





@Rakete1111: There are more uses for null statements than null declarations (that are not also statements).

– Davis Herring
yesterday












1 Answer
1






active

oldest

votes


















9














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.






share|improve this answer


























  • Just to make sure that I understand it correctly: f({a}) can be realized by f(A{a}) or f(B{a}). Since the first is a perfect match, it is a better match than the second, and the call is unambiguous. Now we consider the second case. f({{a}}) can be realized by f(A{A{a}}), f(B{A{a}}), and f(B{B{a}}). The first is prohibited and the second and the third are equally well matches, thus the call is ambiguous. Now consider the third case. f({{{a}}}) can be realized by f(A{A{A{a}}}), f(B{A{A{a}}}), f(B{B{A{a}}}), and f(B{B{B{a}}}). Only the third is not prohibited.

    – user1494080
    yesterday











  • I think I haven't understood it yet. If the problem was that f(B{A{a}}) and f(B{B{a}}) are equally well matches, the call would still be ambiguous when we remove f(const A&). However, the compiler says the opposite.

    – user1494080
    yesterday











  • @user1494080: The ambiguity is between f(A{A{a}}) (only the outer of those two is user-defined) and f(B{A{a}}). f(B{B{a}}) is invalid because the inner conversion is user-defined and so the outer one must not be. Note the asymmetry: {a} -> A is exact-match, but the resulting {B{a}} -> B is user-defined because overload resolution had to occur to identify the {a} -> B conversion.

    – Davis Herring
    yesterday











  • Doesn't f(A{A{a}}) call two times one and the same copy-constructor A(const A&)? How can one be user-defined and the other not?

    – user1494080
    yesterday








  • 1





    @DavisHerring Sorry, I’m still struggling. f(B{B{a}}) is prohibited, because the inner conversion is user-defined (I agree), and the outer conversion is also user-defined (that's how I understand you). However, in the third case f(B{B{A{a}}}) is not prohibited, because the inner conversion is an exact match, the middle conversion is user-defined, and the outer one is again a standard conversion? Why is the first f(B{B{...}}) user-defined and the second f(B{B{...}}) not?

    – user1494080
    22 hours ago











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54504463%2fhow-does-the-number-of-braces-affect-uniform-initialization%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









9














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.






share|improve this answer


























  • Just to make sure that I understand it correctly: f({a}) can be realized by f(A{a}) or f(B{a}). Since the first is a perfect match, it is a better match than the second, and the call is unambiguous. Now we consider the second case. f({{a}}) can be realized by f(A{A{a}}), f(B{A{a}}), and f(B{B{a}}). The first is prohibited and the second and the third are equally well matches, thus the call is ambiguous. Now consider the third case. f({{{a}}}) can be realized by f(A{A{A{a}}}), f(B{A{A{a}}}), f(B{B{A{a}}}), and f(B{B{B{a}}}). Only the third is not prohibited.

    – user1494080
    yesterday











  • I think I haven't understood it yet. If the problem was that f(B{A{a}}) and f(B{B{a}}) are equally well matches, the call would still be ambiguous when we remove f(const A&). However, the compiler says the opposite.

    – user1494080
    yesterday











  • @user1494080: The ambiguity is between f(A{A{a}}) (only the outer of those two is user-defined) and f(B{A{a}}). f(B{B{a}}) is invalid because the inner conversion is user-defined and so the outer one must not be. Note the asymmetry: {a} -> A is exact-match, but the resulting {B{a}} -> B is user-defined because overload resolution had to occur to identify the {a} -> B conversion.

    – Davis Herring
    yesterday











  • Doesn't f(A{A{a}}) call two times one and the same copy-constructor A(const A&)? How can one be user-defined and the other not?

    – user1494080
    yesterday








  • 1





    @DavisHerring Sorry, I’m still struggling. f(B{B{a}}) is prohibited, because the inner conversion is user-defined (I agree), and the outer conversion is also user-defined (that's how I understand you). However, in the third case f(B{B{A{a}}}) is not prohibited, because the inner conversion is an exact match, the middle conversion is user-defined, and the outer one is again a standard conversion? Why is the first f(B{B{...}}) user-defined and the second f(B{B{...}}) not?

    – user1494080
    22 hours ago
















9














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.






share|improve this answer


























  • Just to make sure that I understand it correctly: f({a}) can be realized by f(A{a}) or f(B{a}). Since the first is a perfect match, it is a better match than the second, and the call is unambiguous. Now we consider the second case. f({{a}}) can be realized by f(A{A{a}}), f(B{A{a}}), and f(B{B{a}}). The first is prohibited and the second and the third are equally well matches, thus the call is ambiguous. Now consider the third case. f({{{a}}}) can be realized by f(A{A{A{a}}}), f(B{A{A{a}}}), f(B{B{A{a}}}), and f(B{B{B{a}}}). Only the third is not prohibited.

    – user1494080
    yesterday











  • I think I haven't understood it yet. If the problem was that f(B{A{a}}) and f(B{B{a}}) are equally well matches, the call would still be ambiguous when we remove f(const A&). However, the compiler says the opposite.

    – user1494080
    yesterday











  • @user1494080: The ambiguity is between f(A{A{a}}) (only the outer of those two is user-defined) and f(B{A{a}}). f(B{B{a}}) is invalid because the inner conversion is user-defined and so the outer one must not be. Note the asymmetry: {a} -> A is exact-match, but the resulting {B{a}} -> B is user-defined because overload resolution had to occur to identify the {a} -> B conversion.

    – Davis Herring
    yesterday











  • Doesn't f(A{A{a}}) call two times one and the same copy-constructor A(const A&)? How can one be user-defined and the other not?

    – user1494080
    yesterday








  • 1





    @DavisHerring Sorry, I’m still struggling. f(B{B{a}}) is prohibited, because the inner conversion is user-defined (I agree), and the outer conversion is also user-defined (that's how I understand you). However, in the third case f(B{B{A{a}}}) is not prohibited, because the inner conversion is an exact match, the middle conversion is user-defined, and the outer one is again a standard conversion? Why is the first f(B{B{...}}) user-defined and the second f(B{B{...}}) not?

    – user1494080
    22 hours ago














9












9








9







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.






share|improve this answer















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.







share|improve this answer














share|improve this answer



share|improve this answer








edited 20 hours ago

























answered yesterday









Davis HerringDavis Herring

8,4401635




8,4401635













  • Just to make sure that I understand it correctly: f({a}) can be realized by f(A{a}) or f(B{a}). Since the first is a perfect match, it is a better match than the second, and the call is unambiguous. Now we consider the second case. f({{a}}) can be realized by f(A{A{a}}), f(B{A{a}}), and f(B{B{a}}). The first is prohibited and the second and the third are equally well matches, thus the call is ambiguous. Now consider the third case. f({{{a}}}) can be realized by f(A{A{A{a}}}), f(B{A{A{a}}}), f(B{B{A{a}}}), and f(B{B{B{a}}}). Only the third is not prohibited.

    – user1494080
    yesterday











  • I think I haven't understood it yet. If the problem was that f(B{A{a}}) and f(B{B{a}}) are equally well matches, the call would still be ambiguous when we remove f(const A&). However, the compiler says the opposite.

    – user1494080
    yesterday











  • @user1494080: The ambiguity is between f(A{A{a}}) (only the outer of those two is user-defined) and f(B{A{a}}). f(B{B{a}}) is invalid because the inner conversion is user-defined and so the outer one must not be. Note the asymmetry: {a} -> A is exact-match, but the resulting {B{a}} -> B is user-defined because overload resolution had to occur to identify the {a} -> B conversion.

    – Davis Herring
    yesterday











  • Doesn't f(A{A{a}}) call two times one and the same copy-constructor A(const A&)? How can one be user-defined and the other not?

    – user1494080
    yesterday








  • 1





    @DavisHerring Sorry, I’m still struggling. f(B{B{a}}) is prohibited, because the inner conversion is user-defined (I agree), and the outer conversion is also user-defined (that's how I understand you). However, in the third case f(B{B{A{a}}}) is not prohibited, because the inner conversion is an exact match, the middle conversion is user-defined, and the outer one is again a standard conversion? Why is the first f(B{B{...}}) user-defined and the second f(B{B{...}}) not?

    – user1494080
    22 hours ago



















  • Just to make sure that I understand it correctly: f({a}) can be realized by f(A{a}) or f(B{a}). Since the first is a perfect match, it is a better match than the second, and the call is unambiguous. Now we consider the second case. f({{a}}) can be realized by f(A{A{a}}), f(B{A{a}}), and f(B{B{a}}). The first is prohibited and the second and the third are equally well matches, thus the call is ambiguous. Now consider the third case. f({{{a}}}) can be realized by f(A{A{A{a}}}), f(B{A{A{a}}}), f(B{B{A{a}}}), and f(B{B{B{a}}}). Only the third is not prohibited.

    – user1494080
    yesterday











  • I think I haven't understood it yet. If the problem was that f(B{A{a}}) and f(B{B{a}}) are equally well matches, the call would still be ambiguous when we remove f(const A&). However, the compiler says the opposite.

    – user1494080
    yesterday











  • @user1494080: The ambiguity is between f(A{A{a}}) (only the outer of those two is user-defined) and f(B{A{a}}). f(B{B{a}}) is invalid because the inner conversion is user-defined and so the outer one must not be. Note the asymmetry: {a} -> A is exact-match, but the resulting {B{a}} -> B is user-defined because overload resolution had to occur to identify the {a} -> B conversion.

    – Davis Herring
    yesterday











  • Doesn't f(A{A{a}}) call two times one and the same copy-constructor A(const A&)? How can one be user-defined and the other not?

    – user1494080
    yesterday








  • 1





    @DavisHerring Sorry, I’m still struggling. f(B{B{a}}) is prohibited, because the inner conversion is user-defined (I agree), and the outer conversion is also user-defined (that's how I understand you). However, in the third case f(B{B{A{a}}}) is not prohibited, because the inner conversion is an exact match, the middle conversion is user-defined, and the outer one is again a standard conversion? Why is the first f(B{B{...}}) user-defined and the second f(B{B{...}}) not?

    – user1494080
    22 hours ago

















Just to make sure that I understand it correctly: f({a}) can be realized by f(A{a}) or f(B{a}). Since the first is a perfect match, it is a better match than the second, and the call is unambiguous. Now we consider the second case. f({{a}}) can be realized by f(A{A{a}}), f(B{A{a}}), and f(B{B{a}}). The first is prohibited and the second and the third are equally well matches, thus the call is ambiguous. Now consider the third case. f({{{a}}}) can be realized by f(A{A{A{a}}}), f(B{A{A{a}}}), f(B{B{A{a}}}), and f(B{B{B{a}}}). Only the third is not prohibited.

– user1494080
yesterday





Just to make sure that I understand it correctly: f({a}) can be realized by f(A{a}) or f(B{a}). Since the first is a perfect match, it is a better match than the second, and the call is unambiguous. Now we consider the second case. f({{a}}) can be realized by f(A{A{a}}), f(B{A{a}}), and f(B{B{a}}). The first is prohibited and the second and the third are equally well matches, thus the call is ambiguous. Now consider the third case. f({{{a}}}) can be realized by f(A{A{A{a}}}), f(B{A{A{a}}}), f(B{B{A{a}}}), and f(B{B{B{a}}}). Only the third is not prohibited.

– user1494080
yesterday













I think I haven't understood it yet. If the problem was that f(B{A{a}}) and f(B{B{a}}) are equally well matches, the call would still be ambiguous when we remove f(const A&). However, the compiler says the opposite.

– user1494080
yesterday





I think I haven't understood it yet. If the problem was that f(B{A{a}}) and f(B{B{a}}) are equally well matches, the call would still be ambiguous when we remove f(const A&). However, the compiler says the opposite.

– user1494080
yesterday













@user1494080: The ambiguity is between f(A{A{a}}) (only the outer of those two is user-defined) and f(B{A{a}}). f(B{B{a}}) is invalid because the inner conversion is user-defined and so the outer one must not be. Note the asymmetry: {a} -> A is exact-match, but the resulting {B{a}} -> B is user-defined because overload resolution had to occur to identify the {a} -> B conversion.

– Davis Herring
yesterday





@user1494080: The ambiguity is between f(A{A{a}}) (only the outer of those two is user-defined) and f(B{A{a}}). f(B{B{a}}) is invalid because the inner conversion is user-defined and so the outer one must not be. Note the asymmetry: {a} -> A is exact-match, but the resulting {B{a}} -> B is user-defined because overload resolution had to occur to identify the {a} -> B conversion.

– Davis Herring
yesterday













Doesn't f(A{A{a}}) call two times one and the same copy-constructor A(const A&)? How can one be user-defined and the other not?

– user1494080
yesterday







Doesn't f(A{A{a}}) call two times one and the same copy-constructor A(const A&)? How can one be user-defined and the other not?

– user1494080
yesterday






1




1





@DavisHerring Sorry, I’m still struggling. f(B{B{a}}) is prohibited, because the inner conversion is user-defined (I agree), and the outer conversion is also user-defined (that's how I understand you). However, in the third case f(B{B{A{a}}}) is not prohibited, because the inner conversion is an exact match, the middle conversion is user-defined, and the outer one is again a standard conversion? Why is the first f(B{B{...}}) user-defined and the second f(B{B{...}}) not?

– user1494080
22 hours ago





@DavisHerring Sorry, I’m still struggling. f(B{B{a}}) is prohibited, because the inner conversion is user-defined (I agree), and the outer conversion is also user-defined (that's how I understand you). However, in the third case f(B{B{A{a}}}) is not prohibited, because the inner conversion is an exact match, the middle conversion is user-defined, and the outer one is again a standard conversion? Why is the first f(B{B{...}}) user-defined and the second f(B{B{...}}) not?

– user1494080
22 hours ago


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54504463%2fhow-does-the-number-of-braces-affect-uniform-initialization%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown