例如,以下代码块无法编译:
template <typename T>
void WithOptional(T o1, std::optional<T> o2) {}
int main()
{
WithOptional(1, 1);
}
字符串
下面是编译器错误的一个片段:
could not match 'std::optional' against 'int'
另一方面,这段代码确实可以编译:
template <typename T>
void WithVector(T o1, std::vector<T> o2) {}
int main()
{
WithVector(1, {1});
}
型
我对这里的差异有点困惑。在这两种情况下,第二个参数的类型与参数的类型不同:对于第一个块,我传入了一个int而不是std::optional,而在第二种情况下,传入了一个std::initializer_list而不是std::vector。为什么第二个代码片段可以编译?
1条答案
按热度按时间ut6juiuv1#
{1}
不是std::initializer_list
。它根本不是任何类型:{1}
不是表达式。{1}
实际上是 * 函数调用语法的特殊部分 *,并通过演绎进行特殊处理。具体来说,用作参数的花括号初始化列表不会对模板参数演绎产生影响,除非函数参数已经声明为std::initializer_list
,其引用或数组。因此,在调用
WithVector(1, {1})
中,WithVector
的T
只能从表达式1
推导出来,因为第二个参数既没有声明为std::initializer_list
也没有声明为数组。T
被成功地推导出int
,然后这表明{1}
应该被用来初始化std::vector<int>
。(我不记得引用的参考资料,但委员会使用花括号初始化列表的意图是让它们看起来像表达式,但不是表达式,而是在某些结构下使用的特殊方便语法,例如函数调用和
return
语句。IMO这当然是一个选择。)