I have a question regarding the function template parameter type deduction procedure.
Take this example:
#include <vector>
#include <sstream>
#include <string>
#include <iterator>
#include <fstream>
int main()
{
std::ifstream file("path/to/file");
std::vector<int> vec(std::istream_iterator<int>{file},{}); // <- This part
return 0;
}
If I understand things correctly, the second parameter is deduced to be of type std::istream_iterator
of which the default constructor is called.
The appropriate std::vector
constructor is declared as:
template <class InputIterator>
vector (InputIterator first, InputIterator last,
const allocator_type& alloc = allocator_type());
Since the first parameter type is deduced as std::istream_iterator<int>
the second parameter is deduced as std::istream_iterator<int>
too and so the uniform initialization semantics can be applied. What I have no idea about is at what order the type deduction happens. I would really appreciate some info on this.
Thanks in advance!
Let's use an even simpler example:
template<class T>
void foo(T, T);
foo(42, {});
The function call has two arguments:
int
(an integer literal){}
The latter, {}
, can be part of an expression-list but it is not an expression itself. An expression-list is defined as an initializer-list. braced-init-lists do not have a type.
Template type deduction is done for each function parameter individually [temp.deduct.type]/2. [temp.deduct.call]/1 states about type deduction for a function parameter P
:
If removing references and cv-qualifiers from
P
givesstd::initializer_list<
P'>
for some P' and the argument is an initializer list, then deduction is performed instead for each element of the initializer list, taking P' as a function template parameter type and the initializer element as its argument. Otherwise, an initializer list argument causes the parameter to be considered a non-deduced context. [emphasis mine]
So in the call foo(42, {});
the T
will not be deduced from the second argument {}
. However, T
can be deduced from the first argument.
In general, we can deduce T
from multiple function parameters. In that case, the deduced types have to match exactly [temp.deduct.type]/2. There is no problem if the type is only deduced from one function parameter but used elsewhere (in another function parameter that is in a non-deduced context, in the return type etc). Type deduction can fail e.g. when a template parameter cannot be deduced from any function parameter and is not set explicitly.
After deduction, T
will be substituted by int
, producing a function signature similar to:
void foo<int>(int, int);
This function can be called with the two arguments 42
and {}
. The latter will perform a copy-list-initialization leading to a value-initialization of the second parameter.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With