Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Single-Element-Vector Initialization in a Function Call

Consider the following example code:

Example:

void print(int n) {
    cout << "element print\n";
}

void print(vector<int> vec) {
    cout << "vector print\n";
}

int main() {
   /* call 1 */ print(2);
   /* call 2 */ print({2});
   std::vector<int> v = {2};
   /* call 3 */ print(v);
   /* call 4 */ print( std::vector<int>{2} );
   return 0;
}

which generates the following output:

element print
element print
vector print
vector print

Why the call to print function (call 2 in above example) is getting matched to function accepting a single value? I am creating a vector (containing a single element) in this call, so should it not match to call to print with vector as input?

This is partially discussed in an other question where the provided solution works for vectors with more than 1 elements.

like image 309
Imran Avatar asked Oct 04 '17 12:10

Imran


People also ask

How do you call the first element of a vector?

To get the first element of a vector, we could do the following. In R, array indexes start at 1 - the 1st element is at index 1. This is different than 0-based languages like C, Python, or Java where the first element is at index 0. Notice that for the second example, we put a function inside the square brackets.

What does the vector begin () function return?

vector::begin() begin() function is used to return an iterator pointing to the first element of the vector container. begin() function returns a bidirectional iterator to the first element of the container.


2 Answers

Because the 1st overload wins in the overload resolution for print({2});.

In both cases copy list initialization applies, for the 1st overload taking int,

(emphasis mine)

Otherwise (if T is not a class type), if the braced-init-list has only one element and either T isn't a reference type or is a reference type that is compatible with the type of the element, T is direct-initialized (in direct-list-initialization) or copy-initialized (in copy-list-initialization), except that narrowing conversions are not allowed.

{2} has only one element, it could be used to initialize an int as the argument directly; this is an exact match.

For the 2nd overload taking std::vector<int>,

Otherwise, the constructors of T are considered, in two phases:

  • All constructors that take std::initializer_list as the only argument, or as the first argument if the remaining arguments have default values, are examined, and matched by overload resolution against a single argument of type std::initializer_list

That means an std::initializer_list<int> is constructed and used as the constructor's argument of std::vector<int> (to construct the argument for print). One user-defined conversion (via the constructor of std::vector taking one std::initializer_list) is required, then it's worse match than the 1st overload.

like image 95
songyuanyao Avatar answered Oct 04 '22 21:10

songyuanyao


{2} is a legal initializer for a number of types, including int. Overload resolution prefers a type that exactly matches to one that requires further construction.

like image 42
Caleth Avatar answered Oct 04 '22 21:10

Caleth