C++中的数组扩展类型
据我所知,T[N]中的N的类型是std::size_t。如果有关系的话,我在使用C++17。
template<class T, T N>
void check(char const (&)[N])
{ std::cout << std::is_same_v<std::size_t, T> << '\n'; }
int main()
{
char c[5];
check(c);
return 0;
}
这会输出1。然而,这个不能编译:
template<std::size_t N>
void check(char const (&)[N]) { std::cout << "std::size_t"; }
template<int N>
void check(char const (&)[N]) { std::cout << "int"; }
int main()
{
char c[5];
check(c);
return 0;
}
<source>: In function 'int main()':
<source>:17:12: error: call of overloaded 'check(char [5])' is ambiguous
check(c);
^
<source>:9:6: note: candidate: 'void check(const char (&)[N]) [with long unsigned int N = 5]'
void check(char const (&)[N]) { std::cout << "std::size_t"; }
^~~~~
<source>:12:6: note: candidate: 'void check(const char (&)[N]) [with int N = 5]'
void check(char const (&)[N]) { std::cout << "int"; }
^~~~~
如果N是std::size_t,难道第一种模板重载不是最匹配的吗?我不明白二义性到底来自哪里。
解决方案
在
T[N]中的N的类型是std::size_t。
确实,这意味着这两个重载必须是二义的。
考虑这一要求的含义。每次声明数组时,大小都会隐式转换为std::size_t。就好像每个有效的T[N]都会被替换成T[static_cast<std::size_t>(N)],强调的是“有效”的意思。(如果没有这个替换,编译将失败。举例来说,使用带作用域的枚举(enum class)作为大小时,即使添加了强制转换也不会编译。)对于该问题的代码,这种替换保持了语义。
再看看最后一个模板的声明:
template<int N>
void check(char const (&)[N])
这个参数的类型是什么?它是对数组的引用。由于它是数组,大小必须是std::size_t类型,正如你自己指出的。编译器将此声明视为
template<int N>
void check(char const (&)[static_cast<std::size_t>(N)])
这个转换是在重载解析看到函数签名之前完成的。这个参数的类型与另一模板的参数类型相同。二义性。
请注意,如同你的第一个示例所示,在声明char c[5]中也发生了同样的隐式转换。字面量5的类型是int,并被转换为std::size_t,以形成更准确书写的类型char [5uz](通常在C++23之前写作char [5ull])。只要看到数组类型,大小就必须是std::size_t,无论用于表示大小的表达式的名义类型为何。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。