Home > front end >  Overload resolution of int vs std::vector<int> with an initializer list of a single int
Overload resolution of int vs std::vector<int> with an initializer list of a single int

Time:07-30

Why does c choose a primitive type overload match over a "better" matching initializer list?


#include <vector>

void foo([[maybe_unused]] int i) {}

void foo([[maybe_unused]] const std::vector<int>& v) {}

int main() {
    foo(0);
    foo({1,2,3});
    foo({0}); // calls foo(int) and issues a warning,
              // rather than what seems like the "better"
              // match foo(vector).. why? 
}
<source>:10:9: warning: braces around scalar initializer [-Wbraced-scalar-init]
    foo({0}); // calls foo(int) and issues a warning,
        ^~~

Perhaps "surprising" result, since the compiler chooses the option for which it then issues a diagnostic?

Using Clang 14

https://godbolt.org/z/1dscc5hM4

CodePudding user response:

{0} doesn't have a type, so we need to try and convert it to the parameter types of the overload set. When considering

void foo([[maybe_unused]] const std::vector<int>& v) {}

We need to consult [over.ics.list]/7.2 which states

Otherwise, the implicit conversion sequence is a user-defined conversion sequence whose second standard conversion sequence is an identity conversion.

so we have a user defined conversion for this conversion sequence.

Looking at

void foo([[maybe_unused]] int i) {}

We find the conversion covered in [over.ics.list]/10.1 which states

if the initializer list has one element that is not itself an initializer list, the implicit conversion sequence is the one required to convert the element to the parameter type;

The element in this case is 0, which is an integer literal which is an exact match standard conversion

So now we have a user defined conversion vs a standard conversion and that is covered by [over.ics.rank]/2.1

a standard conversion sequence is a better conversion sequence than a user-defined conversion sequence or an ellipsis conversion sequence, and

and now we know that the standard conversion is a better conversion and that is why the int overload is chosen over the std::vector<int> overload.

  • Related