Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

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

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

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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

>Solution :

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

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading