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
Pgivesstd::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