6

我有一个关于函数模板参数类型推导程序的问题。

举个例子:

#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是调用默认构造函数的类型。

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

template <class InputIterator>
         vector (InputIterator first, InputIterator last,
                 const allocator_type& alloc = allocator_type());

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

提前致谢!

4

1 回答 1

9

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

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

foo(42, {});

函数调用有两个参数:

  • 类型的纯右值表达式int(整数文字)
  • 一个花括号初始化列表 {}

后者 ,{}可以是表达式列表的一部分,但它本身不是表达式。表达式列表被定义为初始化列表大括号初始化列表没有类型。

对每个函数参数单独进行模板类型推导[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);

可以使用两个参数42和调用此函数{}。后者将执行复制列表初始化,导致第二个参数的值初始化。

于 2014-06-05T12:31:32.333 回答