11

Consider this snippet:

#include <iostream>
#include <vector>

void f(std::vector<int>){std::cout << __PRETTY_FUNCTION__ << '\n';}
void f(int x){std::cout << __PRETTY_FUNCTION__ << '\n';}

int main() 
{
    f({42});
}

Live on Coliru

If you run it, you can see that the f(int) overload was preferred, even though std::vector has an std::initializer_list constructor (see #8).

Question: Why is the conversion {42} to int preferred (instead of conversion to std::vector, as {42} is an std::initializer_list)?

vsoftco
  • 55,410
  • 12
  • 139
  • 252
  • This is tagged [c++11] but the linked Coliru is compiled with `-std=c++17`. The inconsistency does not feel right although it does not affect the question. –  Jul 18 '18 at 01:54
  • 5
    `{42}` is not a `std::initializer_list`. It is an `int` in braces. It is not an expression and does not have a type. – M.M Jul 18 '18 at 04:44
  • @NickyC modified – vsoftco Jul 23 '18 at 16:02

1 Answers1

16

In overload resolution, when considers implicit conversion sequence in list-initialization,

(emphasis mine)

Otherwise, if the parameter type is not a class and the initializer list has one element, the implicit conversion sequence is the one required to convert the element to the parameter type

Given f({42});, for f(int), the implicit conversion sequence is the one to convert the element (i.e. 42) to int, which is an exact match; for f(std::vector<int>), user-defined conversion (converting std::initializer_list<int> to std::vector<int>) is required then it's a worse match.

PS: if the braced-initializer contains more than one element such as {42, 42}, f(std::vector<int>) will be selected.

songyuanyao
  • 169,198
  • 16
  • 310
  • 405