Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is Clang or GCC correct in rejecting/accepting this CTAD code?

Tags:

Clang and GCC disagree on accepting this code.

What is the standard required behavior?

#include <utility> #include <iostream> #include <vector>  int main() {     std::vector pairs = {std::pair{1,11},{2,22}, {3,33}};     for (const auto& p: pairs) {         std::cout << p.second << std::endl;     } } 

Note: I know this is C++ so it is possible that the standard is fuzzy, but I presume one behavior is correct.

like image 508
NoSenseEtAl Avatar asked Feb 09 '21 18:02

NoSenseEtAl


1 Answers

The process of CTAD is largely defined by [over.match.class.deduct]. Broadly speaking, the overload set is all of the accessible constructors of the type, plus any deduction guides. And the overload set is resolved per this rule:

Initialization and overload resolution are performed as described in [dcl.init] and [over.match.ctor], [over.match.copy], or [over.match.list] (as appropriate for the type of initialization performed)

Since the "type of initialization performed" is definitely list-initialization, we move on to [over.match.list]. Where we get this infamous bulleted list:

  • 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.

This tells us that initializer-list constructors are prioritized; they're given first crack at overload resolution, and in a very specific way (that is, building a std::initializer_list and passing it as an argument). However, Clang gives a telling error:

note: candidate function template not viable: requires at most 2 arguments, but 3 were provided      vector(initializer_list<value_type> __l, 

That is, it's trying to call that constructor as if "the argument list consists of the elements of the initializer list." This suggests that Clang skipped the first bullet point when doing list-initialization through CTAD. The fact that adding parens around the braced-init-list "fixes" the issue also suggests that this is what is happening.

Oddly, it works for simple types, like an initializer-list of integers. And it works if you explicitly name each member as a pair. And Clang can auto-deduce the type of the initializer_list produced by {std::pair{1,11}, {2,22}, {3,33}} just fine. So this bug seems really specific.

like image 129
Nicol Bolas Avatar answered Oct 30 '22 11:10

Nicol Bolas