我正在尝试基于数学向量编写一个类:
template <unsigned N> class Vector{
public:
Vector() = default;
Vector(std::initializer_list<double> li) { *this = li;}
Vector& operator=(std::initializer_list<double>);
private:
std::array<double, N> x = {}
}
template <unsigned N> inline Vector<N>& Vector<N>::operator=(std::initializer_list<double> li){
if(N != li.size()) throw std::length_error("Attempt to initialise Vector with an initializer_list of different size.");
std::copy(li.begin(), li.end(), x.begin());
return *this;
}
我希望能够编写这样的代码;
Vector<3> a = {1,2,3};
a = {3,5,1};
用户期望编写这样的代码是很自然的,对吧?但是,如果我使用错误大小的初始值设定项列表,我希望发生编译时错误,就像这样std::array
做一样。
std::array<double, 3> a = {2,4,2,4} //compile time error
Vector<3> a = {3,5,1,5} //run-time error as of right now
我的第一个想法是std::array
用作构造函数/操作符参数,这样会发生隐式转换,然后构造函数会劫持std::array
编译时错误。当然,除了我只能写这样的代码:
Vector<3> a({2,3,2}); //fine
Vector<3> b = {2,4,2}; //error, requires two user-defined conversions (list -> array<double,3> -> Vector<3>)
我想也许可以使用 Variadic 成员模板:
template <typename... Args> Vector(Args... li): x({li...}){
static_assert(sizeof...(li) == N);
}
它必须是,typename...
而不是double...
因为非类型参数必须是整数类型。但后来我遇到了一个缩小的转换错误
Vector<2> a = {3,2} //error: narrowing conversion of 'li#0' from 'int' to 'double' inside { } [-Wnarrowing]|
//error: narrowing conversion of 'li#1' from 'int' to 'double' inside { } [-Wnarrowing]|
大概是因为违反 [8.5.4]/7
缩小转换是隐式转换
— 从整数类型或无作用域枚举类型到浮点类型,除非源是常量表达式并且转换后的实际值将适合目标类型并且在转换回原始类型时将产生原始值,或者
扩展的参数li...
不是常量表达式,因此会产生缩小转换错误。据我所知,甚至不可能将函数参数作为常量表达式(也没有多大意义?)。所以我不确定如何沿着这条路线继续前进。显然Vector<2> a = {2.,3.}
工作正常,但这给用户带来了负担,要记住只提供浮点文字。