函数参数绑定通过参考与传递指针传递数组的规则

Function argument binding rules for passing an array by reference vs passing pointer

本文关键字:指针 规则 数组 绑定 参数 参考 函数      更新时间:2023-10-16

为了防止任何混乱,我非常了解数组和指针之间的区别,衰减到点的概念以及通过参考传递数组的概念在C 等。

我的问题是专门关于编译器使用的规则从一组函数 Overload 候选者中选择函数的规则,当一个过载时另一个过载需要指针。

例如,假设我们有:

template <class T, std::size_t N>
void foo(const T (&arr)[N])
{
    std::cout << "Array-reference overload!" << std::endl;
}
template <class T>
void foo(const T* ptr)
{
    std::cout << "Pointer overload!" << std::endl;
}

如果我们尝试调用功能模板foo()如下:

const char arr[2] = "A";
foo(arr);

...然后我的期望是 first Overload(占用数组参考(将由编译器选择。

但是,使用GCC 4.9.2,如果我编译了上述代码,我会发现一个错误:

test.cpp:28:9: error: call of overloaded ‘foo(const char [2])’ is ambiguous

我不清楚为什么在这里编译器将两个过载视为同样好的候选人,因为第一个过载与类型完全匹配,而第二个过载需要一个额外的衰减到分点的步骤。

现在,我可以通过使用type_traits明确使用以下方式来获得以上过载的工作:

template <class T, std::size_t N>
void foo(const T (&arr)[N])
{
    std::cout << "Array-reference overload!" << std::endl;
}
template <class T>
void foo(T ptr, typename std::enable_if<std::is_pointer<T>::value>::type* = 0)
{
    std::cout << "Pointer overload!" << std::endl;
}

在这种情况下,选择了程序编译和进行数组参考的过载。但是,我不明白为什么应该有必要使用此解决方案。我想理解为什么编译器认为需要衰减至销量的函数是同样可能的过载候选者作为数组参考,而当传递的参数非常多。

第一个过载与类型完全匹配,而第二个过载需要一个额外的衰减到点步。

因为在过载分辨率中检查隐式转换序列的排名时,阵列到点转换被认为是确切的匹配,因此第二个过载与第一个级别具有相同的等级。

根据标准,$ 16.3.3.1.1标准转换序列[Over.ICS.SCS]表13 - 转换

Conversion                   Category               Rank         Subclause
No conversions required      Identity               Exact Match
... ...
Array-to-pointer conversion  Lvalue Transformation  Exact Match  [conv.array]
... ...