I recently learnt that we can have more than one default constructor in a class. Then I wrote the following program that compiles with msvc but both clang and gcc fails to compile this.
struct A
{
explicit A(int = 10);
A()= default;
};
A a = {}; //msvc ok but gcc and clang fails here
I want to know which compiler is correct here as per the C++17 standard.
GCC says:
<source>:8:8: error: conversion from '<brace-enclosed initializer list>' to 'A' is ambiguous
8 | A a = {}; //msvc ok but gcc and clang fails here
| ^
<source>:5:3: note: candidate: 'constexpr A::A()'
5 | A()= default;
| ^
<source>:4:12: note: candidate: 'A::A(int)'
4 | explicit A(int = 10);
TLDR;
This is CWG 2856 and the program is well-formed as per the current wording in the standard as descirbed below. Basically, only one of the ctors(
A::A()andexplicit A::A(int)) is a converting constructor. Thus only the formerA::A()is the viable option and can be used.First note that
A a = {};is copy-initialization.Next we move to the semantics of the initializer.
The above means that, the object is to be list-initialized.
From list initialization:
The above means that
A a = {};is copy-list initiaization. Next we see the effect of list initialization:The above means that the object will be value initialized, so we move on to value-initialization:
This means that the object will be default initialized:
So we move on to over.match.ctor to get a list of candidate ctors. Also do note the
initializer()part in the above quoted reference as it will be used at the end as an argument.This means that only the non-explicit ctor
A::A()is the candidate because it is a converting ctor while the otherexplicit A::A(int)is not. Thus the set of candidates and viable options only contains one ctorA::A().Finally, since we only have one viable option, it is the one that is selected for the initializer ().