大括号初始化列表和功能模板类型的推导顺序 [英] Braced-init-lists and function template type deduction order
问题描述
我对功能模板参数类型推导过程有疑问.
I have a question regarding the function template parameter type deduction procedure.
以这个例子为例:
#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;
}
如果我理解正确,第二个参数将推导为默认构造函数称为std::istream_iterator
的类型.
If I understand things correctly, the second parameter is deduced to be of type std::istream_iterator
of which the default constructor is called.
适当的std::vector
构造函数声明为:
The appropriate std::vector
constructor is declared as:
template <class InputIterator>
vector (InputIterator first, InputIterator last,
const allocator_type& alloc = allocator_type());
由于将第一参数类型推导为std::istream_iterator<int>
,因此将第二参数也推导为std::istream_iterator<int>
,因此可以应用统一的初始化语义.我不知道类型推导发生的顺序.我非常感谢您提供一些信息.
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.
提前谢谢!
推荐答案
让我们使用一个更简单的示例:
Let's use an even simpler example:
template<class T>
void foo(T, T);
foo(42, {});
函数调用有两个参数:
- 类型为
int
(整数文字)的prvalue表达式 - 一个括号初始化列表
{}
- a prvalue expression of type
int
(an integer literal) - a braced-init-list
{}
后者{}
可以是 expression-list 的一部分,但它本身不是 expression .一个 expression-list 定义为一个 initializer-list . braced-init-lists 没有类型.
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.
每个功能参数的单独模板类型推导[temp.deduct.type]/2. [temp.deduct.call]/1关于函数参数P
的类型推导的状态:
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
:
如果从
P
中删除引用和简历限定符,则给出std::initializer_list<
P'>
表示某些 P',且参数为 初始化列表,然后对每个元素执行推导 初始化列表列表,以 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]
因此,在调用foo(42, {});
中,不会从第二个自变量{}
推导出T
.但是,可以从第一个参数推导出T
.
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.
通常,我们可以从多个函数参数推导出T
.在这种情况下,推导的类型必须精确匹配[temp.deduct.type]/2.如果类型仅从一个函数参数推导而在其他地方使用(在非推论上下文中的另一个函数参数中,在返回类型中),则没有问题.类型推导可能会失败,例如当无法从 any 函数参数推断出模板参数并且未明确设置模板参数时.
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.
扣除后,T
将被int
替换,产生类似于以下内容的功能签名:
After deduction, T
will be substituted by int
, producing a function signature similar to:
void foo<int>(int, int);
可以使用两个参数42
和{}
调用此函数.后者将执行复制列表初始化,从而导致第二个参数的值初始化.
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.
这篇关于大括号初始化列表和功能模板类型的推导顺序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!