可以抑制或容纳数组指针衰减吗?

问题描述 投票:0回答:1

我想要一个函数重载,其中一个用例通过指针传递非数组参数,而另一个用例通过引用传递 C 数组参数。

不幸的是,传递 C 数组参数会选择两个候选函数,因为 C 数组的指针衰减必须处于同一考虑级别,从而使情况变得不明确。

#include <iostream>

static void foo(int* p) {
    std::cout << "int* -> " << *p << "\n";
}

static void foo(int (&a)[4]) {
    std::cout << "int[4] -> "
        << a[0] << " "
        << a[1] << " "
        << a[2] << " "
        << a[3] << "\n";
}

int main() {
    int array[4]{ 10, 20, 30, 40 };
    foo(array); // error: call to 'foo' is ambiguous
    foo(array + 3);
}

我目前正在使用此解决方法。 我对这个解决方法不满意。

static void foo(int (*a)[4]) { /*...*/ }

...将通过...调用

    foo(&array);

将指针传递更改为指针传递引用的替代方法

void foo(int*& p)
将阻止通过
foo(array + 3)
调用它,因为这是一个右值。

是否有另一种方法(或模板魔法)可以消除这两种情况的歧义?

上下文最好是 C++17,但如果可以用 C++20 或更高版本表达一个不错的解决方案,那仍然会令人感兴趣。

(XY 问题?)原始上下文是将指针或数组作为类构造函数参数进行参数传递。 最初的上下文是尝试创建一个“胖指针”,就像 Google 的 Miracle Pointer 一样,它是常规原始指针的直接替代品,但包含跨度和偏移信息以及偏执检查(这确实会产生额外的运行时开销)。 我尝试将示例简化为突出和最小的重现情况。

更新(回复评论):最终,我也希望它也支持和区分

const int[4]
const int*

c++ arrays
1个回答
0
投票

不幸的是,传递 C 数组参数会选择两个候选函数

所以,你应该人为地让非数组构造函数变得更糟。 @user17732522 的评论中已经提供了最简单的方法。 但如果由于某种原因这对您不起作用,这里有一个较旧的方法:引入用户定义的转换。

template <typename T>
struct RawPtr
{
    [[gnu::always_inline]] constexpr RawPtr(T* ptr)
     : m_ptr(ptr)
    {
    }

    T*      m_ptr;
};

template <typename T>
struct FatPtr
{
    FatPtr(RawPtr<T> p);
    
    template <size_t N>
    FatPtr(T (&p)[N]);
};

template <typename T>
FatPtr(T*) -> FatPtr<T>;

int main()
{
    int         arr[5] = {};
    const char  carr[3] = {};

    FatPtr      t1(arr);
    FatPtr      t2(arr + 3);
    FatPtr      t3(carr);
    FatPtr      t4(carr + 1);
}
© www.soinside.com 2019 - 2024. All rights reserved.