数组的大小是否协变?

时间:2011-01-19 04:21:24

标签: c++ arrays c++11 polymorphism

有没有办法在数组大小中以多态方式使用新的std::array类型?也就是说,如果我有一个

形式的函数
void DoSomething(std::array<int, 5>& myArray) {
    /* ... */
}

然后在数学上定义良好以执行以下操作(即使它不是合法的C ++代码?)

std::array<int, 10> arr;
DoSomething(arr);

Imof这在数学上是明确定义的,有没有办法写std::array使得它的数组元素是连续的并且这个代码编译?我能想到的唯一技术是有一些奇怪的模板元程序,其中std::array<T, N+1>继承自std::array<T, N>,但我不相信这会迫使数组元素连续。

3 个答案:

答案 0 :(得分:5)

直接?没有。

但是,您可以使用编译时多态来实现非常相似的功能,并且可以编写一个引用包装器,以便在代码中更容易使用:

#include <array>
#include <cstddef>

template <typename T, std::size_t N>
struct ref_array_of_at_least
{
    template <std::size_t M>
    ref_array_of_at_least(T (&a)[M])
        : data_(a)
    {
        static_assert(M >= N, "Invalid size");
    }

    template <std::size_t M>
    ref_array_of_at_least(std::array<T, M>& a)
        : data_(&a[0])
    {
        static_assert(M >= N, "Invalid size");
    }

    T* data_;
};

用作:

void f(ref_array_of_at_least<int, 5>) { }

int main()
{
    std::array<int, 5> x;
    std::array<int, 6> y;
    std::array<int, 4> z;
    f(x); // ok
    f(y); // ok
    f(z); // fail
}

(你需要向operator[]添加一些ref_array_of_at_least重载等,并且需要做一些工作才能使它成为正确的,但这是一个开始,证明你正在寻找的东西的可能性。)

答案 1 :(得分:2)

如果这是一项要求,则一种方法是转换运算符到所需类型:

#include <iostream>

template <typename T, int N>
struct Array
{
    Array() { for (int i = 0; i < N; ++i) x[i] = 0; }

    template <int N2>
    operator Array<T, N2>&()
    {
        // for safety, static assert that N2 < N...
        return reinterpret_cast<Array<T, N2>&>(*this);
    }

    int size() const { return N; }
    T x[N];

    friend std::ostream& operator<<(std::ostream& os, const Array& a)
    {
        os << "[ ";
        for (int i = 0; i < N; ++i) os << a.x[i] << ' ';
        return os << ']';
    }
};


void f(Array<int, 5>& a)
{
    a.x[a.size() - 1] = -1;
}

int main()
{
    Array<int, 10> a;
    std::cout << a << '\n';
    f(a);
    std::cout << a << '\n';
}

我不会推荐它:非常可怕。一个更明确的机制似乎更不容易被滥用,而且更强大 - 有点模糊:

template <size_t N2>
Array<T,N2>& slice(size_t first_index)
{
    return *(Array<T,N2>*)(data() + first_index);
}

// usage...
f(a.slice<5>(3));  // elements 3,4,5,6,7.

(清理施法以获得额外的分数: - /)

答案 2 :(得分:0)

不,但你可以伪造它:

// Hide this function however you like: "detail" namespace, use "_detail"
// in the name, etc.; since it's not part of the public interface.
void f_detail(int size, int *data) {
  use(data, /* up to */ data + size);
}

int const f_min_len = 5;

template<int N>
void f(int (&data)[N]) {
  static_assert(N >= f_min_len);
  f_detail(N, data);
}

template<int N>
void f(std::array<int, N> &data) {
  static_assert(N >= f_min_len);
  f_detail(N, &data[0]);
}

这是一个完整的例子,应该完全按照提供的方式工作。您只需要从int更改数据类型(或使其成为模板参数)并根据需要添加const。