【问题标题】:Braced-init-lists and function template type deduction orderBraced-init-lists 和函数模板类型推演顺序
【发布时间】:2014-07-26 10:04:32
【问题描述】:

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

举个例子:

#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&lt;int&gt;,第二个参数也被推导出为std::istream_iterator&lt;int&gt;,因此可以应用统一的初始化语义。我不知道的是类型推导发生的顺序。我非常感谢您提供有关此方面的一些信息。

提前致谢!

【问题讨论】:

  • 有效吗?如果是这样,必须先扣除第一个。

标签: c++ templates c++11 type-deduction list-initialization


【解决方案1】:

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

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

foo(42, {});

函数调用有两个参数:

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

后者{} 可以是表达式列表 的一部分,但它本身不是表达式expression-list 被定义为 initializer-listbraced-init-lists 没有类型。

对每个函数参数单独进行模板类型扣除[temp.deduct.type]/2。 [temp.deduct.call]/1 说明函数参数P的类型推导:

如果从 P 中删除引用和 cv 限定符会给出 std::initializer_list&lt;P'&gt; for some P' 并且参数是 初始化器列表,然后对每个元素执行推导 初始化器列表,以 P' 作为函数模板参数 类型和初始值设定项元素作为其参数。 否则, 初始化器列表参数导致参数被视为 非推断上下文。 [强调我的]

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

一般来说,我们可以从多个函数参数中推导出T。在这种情况下,推导的类型必须完全匹配 [temp.deduct.type]/2。如果类型仅从一个函数参数推导出但在其他地方使用(在非推导上下文中的另一个函数参数中,在返回类型等中),则没有问题。类型扣除可能会失败,例如当模板参数不能从任何函数参数推导出来且没有显式设置时。

推演后,T 将被 int 替换,产生类似于以下的函数签名:

void foo<int>(int, int);

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

【讨论】:

  • 这或多或少是我直观地看到的。感谢您清理一切。
猜你喜欢
  • 2022-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多