8

Consider this simple type:

struct A {
  A(int, int, int)    {} 
  A(std::vector<int>) {}
}; 

///
A a({1,2,3}); 

The snippet above constitutes an ill-formed program, as overload resolution fails because {1, 2, 3} can be used to initialize a temporary A, and so the copy c'tor is viable as well for initializing a.

I initially assumed that marking the first c'tor as explicit A(int, int, int) could be used to resolve the issue. And Clang agrees. On the other hand, GCC still does not accept it, stating the same reason of two viable candidate c'tors.

To make matters worse, this is made even more confusing by another observation. If one was to use list initialization instead, i.e. A a{{1,2,3}};, then suddenly both Clang and GCC accept the code with the original class definition unchanged (where nothing is explicit).

Which compiler is being compliant in the case of A a({1,2,3});?

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • 3
    "Uniform" initialisation my arse – Lightness Races in Orbit Mar 13 '18 at 20:04
  • 1
    @LightnessRacesinOrbit this is **NOT** a uniform initialization. Uniform initialization would take the form of `A a{1,2,3}` - which, by the way, compiles fine. – SergeyA Mar 13 '18 at 20:06
  • @SergeyA: It's a joke, based on the name. See also: https://xkcd.com/927/ – Lightness Races in Orbit Mar 13 '18 at 20:07
  • FWIW the latest MSVC 2017 doesn't like the original code either, producing this error: `error C2668: 'A::A': ambiguous call to overloaded function` while happily compiling the `A a{{1,2,3}};` – YePhIcK Mar 13 '18 at 20:15
  • I want to say GCC is right in the first case since direct initialization considers off of the classes constructors. I have no idea though why `A a{{1,2,3}};` works though. – NathanOliver Mar 13 '18 at 20:40
  • So called _List-initialization_ `A a{{1,2,3}};` seems to be least of the problem. In fact it is the least confusing one. 1st it looks for initializer list argument which there none, then it treats {1,2,3} as single argument which matches vector constructor. `A a{1,2,3};` also fails 1st stage but then (1,2,3) match individual int args. – Killzone Kid Mar 13 '18 at 20:43
  • 1
    See https://stackoverflow.com/q/34622076/4326278, which is linked from this Clang bug report: https://bugs.llvm.org/show_bug.cgi?id=27642. The behaviour in the `A a{{1,2,3}};` case is due to [\[over.best.ics\]/4.5](http://eel.is/c++draft/over.best.ics#4.5). – bogdan Mar 13 '18 at 21:33
  • @bogdan Good find! 2 year old ticket and since even MS fixed this bug in their VS but Clang team seems reluctant. – Killzone Kid Mar 13 '18 at 21:53
  • 1
    @bogdan - I concur with KillzoneKid, this is an excellent find! I have all the normative references I want in the accepted answer, making this a proper dupe. – StoryTeller - Unslander Monica Mar 14 '18 at 05:27
  • @StoryTeller What makes it even more confusing that `A({1,2})` and `A({1,2,3,4})` are both fine and vector overload is chosen, just not `A({1,2,3})`. So the moral of the story, use List-initialization and avoid Copy-list-initialisation :) – Killzone Kid Mar 14 '18 at 08:33

0 Answers0