函数参数绑定规则,用于通过引用传递数组和传递指针

时间:2021-06-21 21:33:24

To prevent any confusion, I very much understand the difference between arrays and pointers, the concept of decay-to-pointer, and the concept of passing an array by reference in C++, etc.

为了防止任何混淆,我非常理解数组和指针之间的区别,衰减到指针的概念,以及在C ++中通过引用传递数组的概念等。

My question here is specifically about the rules used by the compiler to select a function from a set of function overload candidates, when one overload takes an array reference, and the other overload takes a pointer.

这里我的问题具体是关于编译器从一组函数重载候选中选择函数的规则,当一个重载采用数组引用时,另一个重载采用指针。

For example, suppose we have:

例如,假设我们有:

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;
}

If we attempt to invoke function template foo() as follows:

如果我们尝试按如下方式调用函数模板foo():

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

... then my expectation would be that the first overload, the one that takes an array reference, would be selected by the compiler.

...然后我的期望是编译器将选择第一个重载,即采用数组引用的重载。

However, using GCC 4.9.2, if I compile the above code, I get an error:

但是,使用GCC 4.9.2,如果我编译上面的代码,我会收到一个错误:

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

It's unclear to me why both overloads are considered equally good candidates by the compiler here, since the first overload matches the type exactly, whereas the second overload requires an extra decay-to-pointer step.

我不清楚为什么这两个重载被编译器认为是同样好的候选者,因为第一个重载完全匹配类型,而第二个重载需要额外的衰减到指针步骤。

Now, I am able to get the above overload working by explicitly using type_traits as follows:

现在,我可以通过显式使用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;
}

In this case, the program compiles and the overload that takes an array reference is selected. However, I don't understand why this solution should be necessary. I'd like to understand why the compiler considers a function that requires decay-to-pointer an equally likely overload candidate as the array reference, when the argument passed is very much an array.

在这种情况下,程序编译并选择采用数组引用的重载。但是,我不明白为什么这个解决方案应该是必要的。我想理解为什么当传递的参数非常多的数组时,编译器会考虑一个函数,该函数需要将decay-to-pointer作为数组引用同样可能的重载候选。

1 个解决方案

#1


4  

the first overload matches the type exactly, whereas the second overload requires an extra decay-to-pointer step.

第一个重载完全匹配类型,而第二个重载需要额外的衰减到指针步骤。

Because when checking the ranking of implicit conversion sequences in overload resolution, the array-to-pointer conversion is considered as an exact match, thus the 2nd overload has the same rank with the 1st one.

因为在重载决策中检查隐式转换序列的排名时,数组到指针的转换被认为是完全匹配,因此第二个重载与第一个重载具有相同的等级。

From the standard, $16.3.3.1.1 Standard conversion sequences [over.ics.scs] Table 13 — Conversions

从标准,$ 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]
... ...

It's worth noting that the rank of "No conversions required" (i.e. the case for the 1st overload) is "Exact Match" too.

值得注意的是,“无需转换”(即第一次超载的情况)的等级也是“完全匹配”。

#1


4  

the first overload matches the type exactly, whereas the second overload requires an extra decay-to-pointer step.

第一个重载完全匹配类型,而第二个重载需要额外的衰减到指针步骤。

Because when checking the ranking of implicit conversion sequences in overload resolution, the array-to-pointer conversion is considered as an exact match, thus the 2nd overload has the same rank with the 1st one.

因为在重载决策中检查隐式转换序列的排名时,数组到指针的转换被认为是完全匹配,因此第二个重载与第一个重载具有相同的等级。

From the standard, $16.3.3.1.1 Standard conversion sequences [over.ics.scs] Table 13 — Conversions

从标准,$ 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]
... ...

It's worth noting that the rank of "No conversions required" (i.e. the case for the 1st overload) is "Exact Match" too.

值得注意的是,“无需转换”(即第一次超载的情况)的等级也是“完全匹配”。