C++ 数组大小是否协变?
是否有一种方法可以在数组大小中多态地使用新的C++ 数组大小是否协变?,c++,arrays,c++11,polymorphism,C++,Arrays,C++11,Polymorphism,是否有一种方法可以在数组大小中多态地使用新的std::array类型?也就是说,如果我有一个形式的函数 void DoSomething(std::array<int, 5>& myArray) { /* ... */ } void DoSomething(std::array和myArray){ /* ... */ } 那么数学上定义好了做以下(即使它不是合法C++代码)< /P> std::数组arr; 剂量测定法(arr); 如果这在数学上定义得很好,有没
std::array
类型?也就是说,如果我有一个形式的函数
void DoSomething(std::array<int, 5>& myArray) {
/* ... */
}
void DoSomething(std::array和myArray){
/* ... */
}
那么数学上定义好了做以下(即使它不是合法C++代码)< /P>
std::数组arr;
剂量测定法(arr);
如果这在数学上定义得很好,有没有一种方法可以编写std::array
,这样它的数组元素是连续的,并且代码可以编译?我能想到的唯一技术是使用一些奇怪的模板元程序,std::array
继承自std::array
,但我不认为这会直接强制数组元素是连续的。?没有
但是,您可以使用编译时多态性来实现非常类似的功能,并且您可以编写一个引用包装器,使其更易于在代码中使用:
#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_;
};
#包括
#包括
模板
至少\u的结构引用\u数组\u
{
模板
至少(T&a)[M]的参考数组
:数据(a)
{
静态断言(M>=N,“无效大小”);
}
模板
至少引用数组中的数组(std::array&a)
:数据(&a[0])
{
静态断言(M>=N,“无效大小”);
}
T*数据;
};
用作:
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
}
void f(ref\u数组至少\u的\u){
int main()
{
std::数组x;
std::数组y;
std::数组z;
f(x);//好的
f(y);//好的
f(z);//失败
}
(您需要添加一些
操作符[]
重载等内容到ref\u array\u of_至少
,并且需要做一些工作才能使其保持正确,但这是一个开始,证明了您正在寻找的可能性。)不,但您可以伪造它:
// 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]);
}
//隐藏此函数,不管您喜欢什么:“detail”名称空间,使用“\u detail”
//以名义等。;因为它不是公共界面的一部分。
无效f_详图(整数大小,整数*数据){
使用(数据,/*至*/数据+大小);
}
int const f_min_len=5;
模板
无效f(整数和数据)[N]){
静态断言(N>=f\u min\u len);
f_详细信息(N,数据);
}
模板
空f(标准::数组和数据){
静态断言(N>=f\u min\u len);
f_详细信息(N,&数据[0]);
}
这是一个完整的示例,应该完全按照前面介绍的那样工作。您只需将数据类型从int更改为int(或使其成为模板参数),并根据需要添加const。如果这是一项要求,一种方法是将运算符转换为所需类型:
#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';
}
#包括
模板
结构数组
{
数组(){for(inti=0;i friend std::ostream&Operator如果您想要编译时多态性,为什么不在N
上模板化函数,或者如果您想要运行时多态性,为什么不使用std::vector
?@Karl Knechtel-假设我想要一个总是包含“至少五个元素”或“至少十个元素”的数组的函数我可以用模板来实现这一点,但这会导致大量代码重复,并且需要static\u assert
-风格的代码,这并不优雅。我不能用std::vector
静态检查这一点。因此,让函数接受某个大小的数组的想法是一种尝试,类似于C99静态大小的数组参数这可以在编译时检查。我不确定您的示例。具体来说,我不确定我是否理解您所说的“数学上定义良好”的意思。在DoSomething
中,如果您查询std::distance(myArray.begin(),myArray.end())
,你期望结果是什么?5
或10
?@James McNellis-我认为“数学上定义良好”意味着“数组是类型理论数学意义上数组的一个子类型。”我希望它能给出10,因为这是数组的实际长度。@templatetypedef:如果它给出10,那么它就不是数组。如果DoSomething用于其他大小的数组,那么它就不应该将数组作为参数。这是简单的Liskov替换主要内容…不要弄乱。
#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.