I'm trying to get extended variant of std::array
for math vectors (and expose same interface as array
does without boilerplate code). I know about std::valarray
but I want fixed size for proper typing in matrix multiplications. Thus I array
fits perfectly. But when I try to inherit constructor it fails.
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’
This error reported for GCC 4.8.2 and for clang 3.4. Last says that vec2d
have only implicit default/copy/move constructors. Yes, array
have only implicit ctor in contrary to vector
which have ctor from initializer_list
. But since ctors are inherited it is natural to inherit possibility to initialize it in a same way as array
initialized.
Question: Why we have that error instead of expected behavior (similar to array
initialization)?
Note: I that I can write forwarding manually to make it work, but this doesn't look as elegant as ctor inheritance.
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))...}) {}
};
std::array
is designed to be an aggregate, so it intentionally does not define any constructors.
Unfortunately, this means it's not possible to inherit from it and get the same behaviour, as aggregates cannot have base classes.
Why do you need to inherit from std::array
anyway? Do you plan to add any private members? If not, then you could just build your framework around free functions operating on std::array
, or perhaps a typedef to it.
If you really want to inherit from std::array
, you'll have to accept losing the aggregate status and provide any constructors you want yourself.
Note that the answer above applies to C++11 and C++14 only. In C++17, the definition of aggregates was loosened to allow public base classes in them, so simply deriving from std::array
and removing the using
declaration is enought to make the code compile:
struct vec2d : std::array<float, 2>
{ }; // simplified
std::array<float, 2> x = {1, 2};
vec2d z = {1, 2};
I had exactly the same problem, trying to mimic the behavior of numpy
. The way I solved this was to implement a constructor that takes as argument an std::array<float,N>
(with &
or &&
or without anything depending on the needs). The initializer list is then cast automatically to that type, and the right constructor is then called. To be more concrete:
#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;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.