为常量数组和常量指针重载函数

10

我可以使用模板函数来捕获一个数组以及其(编译时)大小,就像这样:

template<int N>
void foo(const int (&)[N]) {
    std::cout << "foo(const int (&)[N])\n";
}

然而,我希望重载foo函数也可以接受指向常量的指针,这样第一个重载将在调用数组类型的函数时使用,第二个重载将在直接调用指针时使用。

void foo(const int *) {
    std::cout << "foo(const int *)\n";
}

int main() {
    int a[1] = { 0 };
    foo(a);
    const int b[1] = { 0 };
    foo(b);
}

在ideone上试一下

这里,对于a,调用了第一个重载函数,而对于b,调用了第二个重载函数。

我猜测对于a,编译器必须执行一次const转换,这意味着foo(const int *)不是完美匹配,但我不知道为什么这不是一个模棱两可的函数调用。

我该如何修改代码才能让两种情况都调用第一个重载函数?


1
这不会发生在std::array中:p - melak47
1个回答

3

为什么它不起作用

在你的例子中,编译器认为这两个重载版本都匹配。这时候就需要重载分辨机制来消除一个并选择最佳匹配。根据草案标准N4527 13.3.3/1.6 最佳可行函数 [over.match.best]:

F1 不是函数模板特化,而 F2 是函数模板特化

在我们的例子中,F1 是 void foo(const int *),而 F2 是 template<int N> void foo(const int (&)[N])。因此,F1 会优先于 F2,因为 F1 不是函数模板特化而 F2 是。

解决方法

在第二个重载版本中使用指针的引用:

void foo(const int *&) {
    std::cout << "foo(const int *)\n";
}

为什么建议的解决方案可行

正如dyp在评论中已经提到的,如果像之前所示一样通过引用传递指针,则此匹配被打破,因为const int *&既不能匹配int*也不能匹配int[N]

在线演示


2
你能解释一下为什么这个方法可行而原始方法不行吗? - Fabian Knorr
1
这个重载函数不适用于非const指针。演示 - rozina
@rozina 我知道,对于非 const 指针,可以有另一个重载 void foo(int *&) - 101010
似乎不是一个有用的重载。也与亚历山大的例子不兼容。 - rozina
2
@trion 当传递一个 const int[N] 时,OP中的两个函数都被认为是重载分辨率的精确匹配。第二个重载不是模板,因此它更受欢迎。在这个答案中,const int *& 无法绑定到 int*int[N] 参数,因为否则可能会将 const int* 分配给它并违反常量正确性(想象一下调用者之后改变所指向的对象)。 - dyp
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接