C++中的数组扩展类型

编程语言 2026-07-12

据我所知,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"; }
      ^~~~~

如果Nstd::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导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章