我做了一个学生作业,抽出了一个旧课程来处理一次制作的多项式。我自己不喜欢床单,但事实证明很难缩小代码,对不起......一切都很好。
决定炫耀加概念,限制“数学”类型。已发布
template<typename T>
requires is_integral_v<T>||is_floating_point_v<T>
class Polynome
同样,一切正常……但如果您使用复数,则不会遵守这些限制。我决定不假思索地使用我需要的算术运算编写一个简单的限制条件。
template<typename T, typename V>
concept PolyAble = requires(T a, V b){ a + b; a * b; };
template<typename T>
requires PolyAble<T,T>
class Polynome
一切都会好起来的——如果你不写乘法。如果您编写它,那么一切都会立即飞向友好的操作员的实施
Polynome<std::common_type_t<U,V>> operator*(const Polynome<U>& a, const V& x)
Polynome<std::common_type_t<U,V>> operator*(const V& x, const Polynome<U>& a)
在这两种情况下,咒骂最终都到了无法计算的地步PolyAble<Polynome<double>,Polynome<double>>
。
所以问题是:首先,我根本不明白为什么要使用这些类型,其次,如何正确指定(如果在这种情况下有必要的话)模板自由函数的要求——在我看来因为他们使用带有分隔符的主类,所以它会在那里工作。
这是整张纸。Visual C++ 2022 编译器,17.6.0。
template<typename T>
concept PolyAble = requires(T a, T b){ a+b; a*b; };
template<typename T>
//requires is_integral_v<T>||is_floating_point_v<T>
requires PolyAble<T>
class Polynome
{
public:
Polynome(size_t n = 0):a(n+1,0){}
Polynome(std::initializer_list<T> cfs)
{
a.insert(a.end(),rbegin(cfs),rend(cfs));
norm();
}
~Polynome() {}
Polynome(const Polynome<T>&) = default;
Polynome& operator=(const Polynome<T>&) = default;
Polynome(Polynome<T>&&) = default;
Polynome& operator=(Polynome<T>&&) = default;
size_t extent() { return a.size()-1; }
T operator[](size_t i) const { return (i >= a.size()) ? T(0) : a[i]; }
std::vector<T> coeffs() const { return a; }
template<typename U>
auto operator()(const U& x) -> std::common_type_t<U,T>
{
std::common_type_t<U,T> res = std::common_type_t<U,T>();
for(auto c = a.rbegin(); c != a.rend(); ++c)
{
res = res*x + *c;
}
return res;
}
template<typename U, typename V>
friend Polynome<std::common_type_t<U,V>> operator+(const Polynome<U>& a, const Polynome<V>& b);
template<typename U, typename V>
friend Polynome<std::common_type_t<U,V>> operator-(const Polynome<U>& a, const Polynome<V>& b);
template<typename U, typename V>
friend Polynome<std::common_type_t<U,V>> operator*(const Polynome<U>& a, const V& x);
template<typename U, typename V>
friend Polynome<std::common_type_t<U,V>> operator*(const V& x, const Polynome<U>& a);
template<typename U, typename V>
friend Polynome<std::common_type_t<U,V>> operator*(const Polynome<U>& p, const Polynome<V>& q);
template<typename U>
friend std::ostream& operator<<(std::ostream&,const Polynome<U>&);
private:
std::vector<T> a;
void norm() {
for(auto i = a.rbegin(); i != a.rend(); i = a.rbegin())
if (*i == T(0)) a.erase(i.base()-1); else break;
if (a.empty()) a.push_back(T{});
}
};
template<typename T>
std::ostream& operator<<(std::ostream&os,const Polynome<T>&p)
{
os << "(";
for(auto i = p.a.rbegin(); i != p.a.rend(); ) { os << *i; if (++i != p.a.rend()) os << ","; }
return os << ")";
}
template<typename U, typename V>
Polynome<std::common_type_t<U,V>> operator+(const Polynome<U>& a, const Polynome<V>& b)
{
size_t N = std::max(a.a.size(),b.a.size());
Polynome<std::common_type_t<U,V>> p(N-1);
for(size_t i = 0; i < N; ++i) p.a[i] = a[i] + b[i];
p.norm();
return p;
}
template<typename U, typename V>
Polynome<std::common_type_t<U,V>> operator-(const Polynome<U>& a, const Polynome<V>& b)
{
size_t N = std::max(a.a.size(),b.a.size());
Polynome<std::common_type_t<U,V>> p(N-1);
for(size_t i = 0; i < N; ++i) p.a[i] = a[i] - b[i];
for(auto i = p.a.rbegin(); i != p.a.rend(); i = p.a.rbegin())
if (*i == std::common_type_t<U,V>{}) p.a.erase(i.base()-1); else break;
p.norm();
return p;
}
template<typename U, typename V>
Polynome<std::common_type_t<U,V>> operator*(const Polynome<U>& a, const V& x)
{
Polynome<std::common_type_t<U,V>> p(a.a.size()-1);
for(size_t i = 0; i < a.a.size(); ++i) p.a[i] = a.a[i]*x;
p.norm();
return p;
}
template<typename U, typename V>
Polynome<std::common_type_t<U,V>> operator*(const V& x, const Polynome<U>& a)
{
return a*x;
}
template<typename U, typename V>
Polynome<std::common_type_t<U,V>> operator*(const Polynome<U>& p, const Polynome<V>& q)
{
Polynome<std::common_type_t<U,V>> r(p.a.size()+q.a.size()-2);
for(size_t i = 0; i < p.a.size(); ++i)
for(size_t j = 0; j < q.a.size(); ++j) r.a[i+j] += p[i]*q[j];
r.norm();
return r;
}
using Poly = Polynome<double>;
int main(int argc, char * argv[])
{
double x[5] = {3,4,5,6,7};
double y[5];
Poly org{1.,2.,3.,0.,0.,0.,-3.};
for(int i = 0; i < 5; ++i) y[i] = org(x[i]);
vector<Poly> L(5,Poly{1});
for(int i = 0; i < 5; ++i)
{
for(int j = 0; j < 5; ++j)
if (i != j)
L[i] = L[i]*Poly{1,-x[j]}*(1.0/(x[i]-x[j]));
cout << i << ": " << L[i] << endl;
}
}
由于构造函数的存在,
Polynome(size_t n = 0)
转换是允许的double -> Polynome<double>
。于是std::common_type_t<double, Polynome<double> >
返回Polynome<double>
。此外,当多项式乘以多项式时,编译器会从三个选项中进行选择:
此外,所有三个选项都是合适的,尽管它们具有不同类型的结果。特别是,第一个选项返回
Polynome< Polynome<double> >
。只要为多项式定义了两个运算符(加法和乘法),此选项就是合法的。他为什么要咒骂static_assert( PolyAble<Poly> );
?因为当您尝试检查 operator 的存在时Poly{} * Poly{}
,它再次引用 PolyAble - 递归。