为何第一个C++函数可正常运行,第二个却无法编译?
为什么带条件运算符的代码无法匹配模板构造函数?
先看这段可以正常编译的代码:
struct MyStringView { template <int N> MyStringView(const char(&arr)[N]) : str(&arr[0]), size(N - 1){ } const char* str; int size; }; MyStringView getName(int number) { switch (number) { case 1: return "One"; case 2: return "Two"; case 3: return "Three"; } } int main() { auto string_view = getName(1); }
这段代码能运行的核心原因:当直接返回字符串字面量(比如"One")时,它的类型是const char[4](包含末尾的空字符)。编译器会匹配MyStringView的模板构造函数,自动推导模板参数N=4,通过数组引用的方式构造对象——虽然数组在某些场景下会退化为指针,但这里是先匹配了接收数组引用的模板构造,所以不需要const char*的构造函数也能正常工作。
但下面这段代码会编译失败:
template <bool bAsInteger> MyStringView getName2(int number) { switch (number) { // 编译错误:无法从const char*转换为MyStringView // 但写成 return bAsInteger ? MyStringView("1") : MyStringView("One") 就能正常运行 case 1: return bAsInteger ? "1" : "One"; case 2: return bAsInteger ? "2" : "Two"; case 3: return bAsInteger ? "3" : "Three"; } } int main() { auto string_view = getName2<true>(1); }
问题出在三元运算符的类型规则
C++的三元运算符要求两个分支的类型必须兼容且能统一为同一类型。这里"1"的类型是const char[2],"One"是const char[4],这两个是不同长度的字符数组类型,编译器无法直接统一它们的数组类型,于是会触发数组退化为指针的规则——把两个操作数都转换成const char*类型。
此时整个三元表达式的结果类型就是const char*,而MyStringView的模板构造函数需要的是数组引用,模板参数N无法从const char*推导出来(指针没有数组长度信息),编译器找不到能接收const char*的构造函数,自然就报转换错误了。
而注释里提到的return bAsInteger ? MyStringView("1") : MyStringView("One")能运行,是因为两个分支都是MyStringView类型,三元表达式的结果直接就是MyStringView,不需要再做类型转换,所以能正常返回。
内容的提问来源于stack exchange,提问作者Zebrafish
相关产品推荐
相关产品推荐

