指针衰减优先于模板推导
在编写对字符串进行操作的代码时,通常会遇到尝试重载的困境同时容纳基于数组和非基于数组的字符串表示形式的函数可能会导致意外的结果
在此特定场景中,定义了一个初始函数 foo 来打印字符数组的长度:
template <size_t N> void foo(const char (&s)[N]) { std::cout << "array, size=" << N-1 << std::endl; }
此函数接受字符数组并输出数组长度。但是,当扩展 foo 来处理非数组字符串时,会出现歧义:
void foo(const char* s) { std::cout << "raw, size=" << strlen(s) << std::endl; }
目的是让第二个 foo 重载来处理非数组字符串,但令人惊讶的是,此扩展导致数组和非数组的原始重载被绕过strings:
foo("hello") // prints raw, size=5
这种意外行为源于指针衰减的概念。数组本质上是指向其第一个元素的指针,将数组转换为指针是一个非常便宜的操作。因此,编译器会优先考虑接受指针参数的重载,即使它需要从数组参数进行隐式转换。
为了确保所需的行为,其中基于数组的重载用于数组,有必要引入一个额外的重载:
template <typename T> auto foo(T s) -> std::enable_if_t<std::is_convertible<T, char const*>{}> { std::cout << "raw, size=" << std::strlen(s) << std::endl; }
此重载使用模板推导并将其适用性限制为可以转换为字符指针的类型。通过部分排序,编译器现在可以根据参数类型正确选择适当的 foo 函数。
以上是为什么 C 函数重载中指针衰减会覆盖模板推导?的详细内容。更多信息请关注PHP中文网其他相关文章!