当多个参数使用相同的模板类型时,模板类型推导如何工作?(C++20)

btqmn9zl  于 2024-01-09  发布在  其他
关注(0)|答案(1)|浏览(125)

例如,以下代码块无法编译:

  1. template <typename T>
  2. void WithOptional(T o1, std::optional<T> o2) {}
  3. int main()
  4. {
  5. WithOptional(1, 1);
  6. }

字符串
下面是编译器错误的一个片段:
could not match 'std::optional' against 'int'
另一方面,这段代码确实可以编译:

  1. template <typename T>
  2. void WithVector(T o1, std::vector<T> o2) {}
  3. int main()
  4. {
  5. WithVector(1, {1});
  6. }


我对这里的差异有点困惑。在这两种情况下,第二个参数的类型与参数的类型不同:对于第一个块,我传入了一个int而不是std::optional,而在第二种情况下,传入了一个std::initializer_list而不是std::vector。为什么第二个代码片段可以编译?

ut6juiuv

ut6juiuv1#

{1}不是std::initializer_list。它根本不是任何类型:{1}不是表达式。{1}实际上是 * 函数调用语法的特殊部分 *,并通过演绎进行特殊处理。具体来说,用作参数的花括号初始化列表不会对模板参数演绎产生影响,除非函数参数已经声明为std::initializer_list,其引用或数组。
因此,在调用WithVector(1, {1})中,WithVectorT只能从表达式1推导出来,因为第二个参数既没有声明为std::initializer_list也没有声明为数组。T被成功地推导出int,然后这表明{1}应该被用来初始化std::vector<int>
(我不记得引用的参考资料,但委员会使用花括号初始化列表的意图是让它们看起来像表达式,但不是表达式,而是在某些结构下使用的特殊方便语法,例如函数调用和return语句。IMO这当然是一个选择。)

相关问题