为什么 const char[] 的类型推导不同于 const char *?

Why is type deduction on const char[] different to const char *?

在第一次调用中,当我将 char const [] 传递给参数为 T const a 的模板函数时,T 被推断为 char const * 这是合理的,因为const指的是衰减指针。

但是,当参数类型更改为T const & a时,T被推导为char[7]。从上面的观点来看,为什么 const 没有限定整个数组类型?

template <typename T>
void show1(T const a) {
     // input is const char *
     // T is char const *
     // a is char const * const
}

template <typename T>
void show2(T const & a) {
     // input is char const [7]
     // T is char[7]
     // a is char const (&)[7]
}

int main() {
    const char s[] = "asdasd";
    show1(s);
    show2(s);
}

why doesn't the const qualify the whole array type

因为 array type,

(强调我的)

Applying cv-qualifiers to an array type (through typedef or template type manipulation) applies the qualifiers to the element type, but any array type whose elements are of cv-qualified type is considered to have the same cv-qualification.

// a and b have the same const-qualified type "array of 5 const char"
typedef const char CC;
CC a[5] = {}; 
typedef char CA[5];
const CA b = {};

这意味着当Tchar[7]T const导致类型char const[7],那么T const&(即a的类型) 是 char const (&)[7].

另一方面,当您传递类型为 const char[7] 的数组 s 时,该数组也被视为 const-qualified。因此给定参数类型 T const&T 被推断为 char[7](但不是 char const[7])。

这是因为数组在 C++ 中是 non-copyable 和 non-assignable。

因此在调用 show1 时,const char[] 类型衰减为 const char*。该语言允许在函数调用站点对每个参数进行一次隐式转换。

使用 show2,您通过引用传递 - 不需要复制或赋值,因此不会发生指针衰减。

template <typename T>
void show(ParameterType a) {
}

show(expression);

编译器使用 expression 推导 TParameterType。如果 ParameterType 包含诸如 const.

之类的限定符,则 TParameterType 是不同的

如果 ParameterType 既不是指针也不是引用(你的 show1 的情况,T const),T 的类型是没有 constexpression 的类型, volatile 和参考。所以 Tconst char * 的类型。 ParameterTypea 的类型)是 const char * const

如果 ParameterType(您的 show2 中的 T const &)是指针或引用(但不是像 T&& 那样的引用)。首先忽略引用,它给出结果 T const(与 const T 相同)。 expression (const char []) 到 const T 的第二个匹配类型,所以 Tchar [].

更多信息,Item 1 of Effective Modern C++ by Scott Meyers正是您想要的。规则比我在这里描述的更复杂,但非常重要。