简体   繁体   English

如何正确地使 function 重载指针和 arrays

[英]How can I make a function overloaded for pointers and arrays correctly

I have this overloaded function in C++:我在 C++ 中有这个重载的 function:

template<std::size_t N>
void func(const int(&)[N]) {
    std::cout << "1";
}

void func(const int*) {
    std::cout << "2";
}

If I call func with a pointer, the second overload is called.如果我用指针调用 func ,则会调用第二个重载。 This is expected.这是意料之中的。

const int* p{};
func(p);
// prints 2 - OK

If I call func with an int array, the first overload is called.如果我用 int 数组调用 func,则调用第一个重载。 This is also expected.这也是意料之中的。

int ints[]{1, 2, 3, 4, 5};
func(ints);
// prints 1 - OK

However, if I have call func with an array of const ints, I expect the first overload to be called, but the second is called instead.但是,如果我使用 const ints 数组调用 func,我希望调用第一个重载,但调用第二个重载。

const int ints[]{1, 2, 3, 4, 5};
func(ints);
// prints 2 - NOT OK, 1 is expected

My question is why and how could I write the function func to have the first overload called for const arrays as well?我的问题是为什么以及如何编写 function func以使第一个重载也调用 const arrays? I need the array size in a template parameter, so anything like strlen is not a possible solution for me.我需要模板参数中的数组大小,所以像 strlen 这样的东西对我来说不是一个可能的解决方案。

(It behaves the same way for other types too, like std::string.) (对于其他类型,它的行为方式也相同,例如 std::string。)

Actually expectation should be that both functions are okey for the lines:实际上期望应该是这两个功能对于这些行来说都是好的:

const int ints[]{1, 2, 3, 4, 5};
func(ints);

The only reason you do not get error it is because of it is a template.你没有得到错误的唯一原因是因为它是一个模板。 If you extract the first function from template you will get a compile error about ambiguity which is:如果您从模板中提取第一个 function,您将收到关于歧义的编译错误,即:

error: call of overloaded 'func(const int [5])' is ambiguous错误:重载 'func(const int [5])' 的调用不明确

If you edit your code accordingly:如果您相应地编辑代码:

void func(const int(&)[5]) {
    std::cout << "1"<<std::endl;
}

void func(const int*) {
    std::cout << "2"<<std::endl;
}



int main()
{



    int ints[]{1, 2, 3, 4, 5};
    func(ints);

    const int ints2[]{1, 2, 3, 4, 5};
    func(ints2);

    return 0;
}

In general you should not expect this overload resolution to work.通常,您不应期望此重载解决方案起作用。 An array-to-pointer conversion is equally good as an identity conversion.数组到指针的转换与单位转换一样好。

What you need to do is forcibly remove the second overload from consideration when the first overload is usable.您需要做的是在第一个重载可用时强行删除第二个重载。 This can be done easily in C++20:这可以在 C++20 中轻松完成:

template <std::size_t N>
constexpr int func(const int(&)[N]) {
    return 1;
}

namespace detail { 
template <std::size_t N>
constexpr int dummy_func(const int(&)[N]);
}

template <class T>
constexpr int func(T&& r)
requires std::is_convertible_v<T, int const*> &&
         (!requires { detail::dummy_func(std::forward<T>(r)); }) {
    return 2;
}

Now you'll get the overload resolution behaviour that you want:现在您将获得所需的重载解析行为:

int main() {
    constexpr int const* p = nullptr;
    static_assert(func(p) == 2);

    int const ca[5] = {1, 2, 3, 4, 5};
    static_assert(func(ca) == 1);

    int a[5] = {1, 2, 3, 4, 5};
    static_assert(func(a) == 1);
}

Note that this solution is "imperfect" in some ways.请注意,此解决方案在某些方面是“不完美的”。 The second overload will not be able to accept some arguments that a true const int* parameter can accept, namely an empty braced-init-list or a braced-init-list with a single element that can be converted to const int* .第二个重载将无法接受一些真正的const int*参数可以接受的 arguments,即空的braced-init-list 或带有可以转换为const int*的单个元素的braced-init-list。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM