Braced-init-lists和函数模板类型推导顺序

Ver*_*tas 6 c++ templates c++11 list-initialization type-deduction

我有关于函数模板参数类型推导过程的问题.

举个例子:

#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;
}
Run Code Online (Sandbox Code Playgroud)

如果我理解正确,第二个参数推断为std::istream_iterator默认构造函数的类型.

适当的std::vector构造函数声明为:

template <class InputIterator>
         vector (InputIterator first, InputIterator last,
                 const allocator_type& alloc = allocator_type());
Run Code Online (Sandbox Code Playgroud)

由于推导出第一个参数类型,因为std::istream_iterator<int>第二个参数也被推导出来std::istream_iterator<int>,因此可以应用统一初始化语义.我不知道的是类型推导发生的顺序.我真的很感激这方面的一些信息.

提前致谢!

dyp*_*dyp 9

让我们使用一个更简单的例子:

template<class T>
void foo(T, T);

foo(42, {});
Run Code Online (Sandbox Code Playgroud)

函数调用有两个参数:

  • 类型的prvalue表达式int(整数文字)
  • 一个braced-init-list {}

后者{}可以是表达式列表的一部分,但它本身不是表达式.一个表达式列表被定义为初始列表.braced-init-lists没有类型.

模板类型推导分别针对每个函数参数[temp.deduct.type]/2进行.[temp.deduct.call]/1表示关于函数参数的类型推导P:

如果从某些P'中删除引用和cv限定符P给出 std::initializer_list<P'并且参数是初始化列表,则对初始化列表的每个元素执行推导,将P'作为函数模板参数类型并将初始化元素作为它的论点.否则,初始化列表参数会将参数视为非推导的上下文.[强调我的]>

因此在调用foo(42, {});T不会从第二个参数中推断出{}.但是,T可以从第一个参数推断出来.

通常,我们可以T从多个函数参数中推断出来.在这种情况下,推导出的类型必须与[temp.deduct.type]/2完全匹配.如果类型仅从一个函数参数推导出来但在别处使用(在非推导上下文中的另一个函数参数中,在返回类型中等),则没有问题.类型推导可能会失败,例如,当模板参数无法从任何函数参数推导出来且未明确设置时.

扣除后,T将被替换int,产生类似于的函数签名:

void foo<int>(int, int);
Run Code Online (Sandbox Code Playgroud)

这个功能可以用两个参数来调用42{}.后者将执行复制列表初始化,从而导致第二个参数的值初始化.