Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

If you look at the following code, I think that both the lines in main() should call the initializer_list constructor for InitSomething. gcc outputs 22 as I expected, but clang just outputs a single 2. Is clang wrong?

I am compiling with -std=c++14.

#include <iostream>

struct InitSomething {
    explicit InitSomething(int) { std::cout << '1'; }
    InitSomething(std::initializer_list<int> ) { std::cout << '2'; }
    operator int() { return 1; }
};

int main() {
    InitSomething init_something{1};
    InitSomething init_something_else{init_something};
}

The output of clang++ --version (I am on a mac) is

Apple LLVM version 7.3.0 (clang-703.0.31)
Target: x86_64-apple-darwin15.5.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

and the output of g++ --version on the other platform I mentioned is

g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-4)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
174 views
Welcome To Ask or Share your Answers For Others

1 Answer

DR1467's title concerns aggregates, but the wording it added to [dcl.init.list]/3 as the first bullet is not limited to aggregates:

If T is a class type and the initializer list has a single element of type cv U, where U is T or a class derived from T, the object is initialized from that element (by copy-initialization for copy-list-initialization, or by direct-initialization for direct-list-initialization).

However, DR2137 walked back from this wording (replacing "a class type" with "an aggregate class"), and so this bullet no longer applies to non-aggregates like InitSomething.

Instead, [dcl.init.list]/3.6 applies, like it did pre-DR1467:

Otherwise, if T is a class type, constructors are considered. The applicable constructors are enumerated and the best one is chosen through overload resolution ([over.match], [over.match.list]).

And [over.match.list] makes clear that initializer-list constructors are preferred if at all viable:

When objects of non-aggregate class type T are list-initialized such that [dcl.init.list] specifies that overload resolution is performed according to the rules in this section, overload resolution selects the constructor in two phases:

  • Initially, the candidate functions are the initializer-list constructors ([dcl.init.list]) of the class T and the argument list consists of the initializer list as a single argument.
  • If no viable initializer-list constructor is found, overload resolution is performed again, where the candidate functions are all the constructors of the class T and the argument list consists of the elements of the initializer list.

All this talk about ranking implicit conversion sequences is irrelevant because the non-initializer-list constructors are not even candidates.

Clang is implementing the wording after DR1467 and before DR2137.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...