我正在尝试为数学向量获取std::array
的扩展变体(并且在没有样板代码的情况下公开与array
相同的接口)。我知道std::valarray
但是我想要固定大小以便在矩阵乘法中正确输入。因此我array
非常适合。但是当我尝试继承构造函数时,它失败了。
struct vec2d : std::array<float, 2>
{ using array::array; }; // simplified
struct vec : std::vector<float>
{ using vector::vector; };
std::array<float, 2> x = {1, 2};
vec y = {1, 2};
vec2d z = {1, 2}; // error: could not convert ‘{1, 2}’
// from ‘<brace-enclosed initializer list>’ to ‘vec2d’
GCC 4.8.2和clang 3.4报告了此错误。最后说vec2d
只有隐式的默认/复制/移动构造函数。是的,array
只有隐含的ctor与vector
相反,而initializer_list
来自array
。但由于ctors是遗传的,因此继承初始化它的可能性与array
初始化的方式相同。
问题:为什么我们有错误而不是预期的行为(类似于struct vec2d : std::array<float, 2>
{
using array::array;
// nasty boilerplate code I don't want to have in C++11
template <typename... Args>
vec2d(Args &&... args) : array({float(std::forward<Args>(args))...}) {}
};
初始化)?
注意:我可以手动编写转发以使其正常工作,但这看起来不像ctor继承那么优雅。
{{1}}
答案 0 :(得分:7)
std::array
被设计为聚合,因此它故意不定义任何构造函数。
不幸的是,这意味着不可能继承它并获得相同的行为,因为聚合不能有基类。
为什么你还需要继承std::array
?你打算加入任何私人会员吗?如果没有,那么你可以围绕在std::array
上运行的自由函数构建你的框架,或者对它进行typedef。
如果你真的想继承std::array
,你必须接受失去聚合状态并提供你想要的任何构造函数。
请注意,上面的答案仅适用于C ++ 11和C ++ 14。在C ++ 17中,聚合的定义被放宽以允许公共基类,因此只需从std::array
派生并删除using
声明就可以使代码编译:
struct vec2d : std::array<float, 2>
{ }; // simplified
std::array<float, 2> x = {1, 2};
vec2d z = {1, 2};
答案 1 :(得分:1)
我遇到了完全相同的问题,试图模仿numpy
的行为。
我解决这个问题的方法是实现一个构造函数,该构造函数将std::array<float,N>
作为参数(&
或&&
或根据需要没有任何内容)。
然后将初始化列表自动转换为该类型,然后调用正确的构造函数。更具体一点:
#include <array>
#include <ostream>
#include <iostream>
using namespace std;
template <int N> class Row: public array<double,N>{
public:
Row<N>(){}
// this is the constructor needed
Row<N>(array<double,N> a) : array<double,N> (a) {}
// or, alternatively,
// Row<N>(array<double,N>&& a) : array<double,N> (a) {}
Row<N>(array<double,N>& a) : array<double,N> (a) {}
// other things that may be relevant
Row<N> operator+(Row<N>& other){
Row<N> result;
for(int i =0; i < N ; ++i){
result[i] = (*this)[i] + other[i]; // notice '*'
}
return result;
}
// for lvalues
template <int n> friend ostream& operator<<(ostream& os, Row<n>& r);
// for rvalues
template <int n> friend ostream& operator<<(ostream& os,Row<n>&& r);
};
// for lvalues
template <int N> ostream& operator<<(ostream& os, Row<N>& r){
for(int i =0; i < N ; ++i) os << r[i] << "\t";
return os;
}
// for rvalues
template <int N> ostream& operator<<(ostream& os, Row<N>&& r){
for(int i =0; i < N ; ++i) os << r[i] << "\t";
return os;
}
int main(){
// here Row(array<double,3>&&) is called
// or Row(array<double,3>)
Row<3> a{{1,2,3}}; // same as Row<3> a({1,2,3});
array<double,3> arr = {1,2,3};
Row<3> b(arr);
cout << a << endl; // a and b are lvalues
cout << b << endl;
cout << (a+b) << endl; // (a+b) is a rvalue
return 0;
}