我不太明白使用这些接口有什么好处以及在 C# 中可以在哪里使用它们。因此,据我了解,IEqualityComparer 使用基于哈希表的集合,但我不太明白为什么以及它能带来什么好处。我将非常感谢您澄清情况!
我做了一个学生作业,抽出了一个旧课程来处理一次制作的多项式。我自己不喜欢床单,但事实证明很难缩小代码,对不起......一切都很好。
决定炫耀加概念,限制“数学”类型。已发布
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;
}
}
总的来说,在这个问题之后,我决定写一个例子,但不幸的是我没有掌握它😢。也许你们中的一个可以帮我完成它。
我们有这样一类人
class Person
{
public Person(string firstName, string lastName,
Address address, Employment employment)
{
FirstName = firstName;
LastName = lastName;
Address = address;
Employment = employment;
}
public string FirstName { get; }
public string LastName { get; }
public Address Address { get; }
public Employment Employment { get; }
public override string ToString()
{
return $"{FirstName} {LastName}: "
+ Environment.NewLine +
$"{Address}"
+ Environment.NewLine +
$"{Employment}";
}
}
与同伴课程
class Address
{
public string City { get; set; }
public int PostCode { get; set; }
public override string ToString()
{
return $"Адрес: {City}-{PostCode} ";
}
}
class Employment
{
public string CompanyName { get; set; }
public string Position { get; set; }
public int AnnualIncome { get; set; }
public override string ToString()
{
return $"Работа: {CompanyName}, должность: {Position}, зарплата: {AnnualIncome}";
}
}
独立设法只编写这样一个构建器
class PersonBuilder
{
//аккумулятор названий свойств и их значений
private readonly Dictionary<string, object> _propertiesToBuild;
public PersonBuilder()
{
_propertiesToBuild = new Dictionary<string, object>();
}
//запоминание в словаре названия свойства и его значения
public PersonBuilder Set<T>(Expression<Func<Person, T>> expression, T value)
{
var propertyName = ((MemberExpression)expression.Body).Member.Name;
_propertiesToBuild.Add(propertyName, value);
return this;
}
public T Include<T>(Expression<Func<Person, T>> expression)
{
var propertyName = ((MemberExpression)expression.Body).Member.Name;
if (propertyName == nameof(Person.Address))
{
var result = new Address();
return (T)(object)result;
}
else
{
var result = new Employment();
return (T)(object)result;
}
}
//создание экземпляра на основе значений свойств из словаря
public Person Build()
{
return new Person
(
firstName: GetPropertyValue<string>(nameof(Person.FirstName), "Неизвестно"),
lastName: GetPropertyValue<string>(nameof(Person.LastName), "Неизвестно"),
address: new Address(),
employment: new Employment()
);
}
private T GetPropertyValue<T>(string propertyName, T defaultValue)
{
return _propertiesToBuild.TryGetValue(propertyName, out var value) ? (T)value : defaultValue;
}
}
虽然它是这样工作的
var person = new PersonBuilder()
.Set(p => p.FirstName, "Андрей")
.Set(p => p.LastName, "Иванов")
.Build();
或者
Address address = new PersonBuilder()
.Set(p => p.FirstName, "Андрей")
.Set(p => p.LastName, "Иванов")
.Include(p => p.Address);
或者像这样
Employment employment = new PersonBuilder()
.Set(p => p.FirstName, "Андрей")
.Set(p => p.LastName, "Иванов")
.Include(p => p.Employment);
我希望结果是这样的
Person person = new PersonBuilder()
.Set(p => p.FirstName, "Андрей")
.Set(p => p.LastName, "Иванов")
.Include(p => p.Address)
.Set(a => a.City, "Москва")
.Include(p => p)
.Include(p => p.Employment)
.Set(e => e.Position, "инженер")
.Include(p => p)
.Build();
PS结果版本在这里,谢谢@Vasek
如何在不使用指令的情况下将寄存器的值减一dec?如果可能的话,有几种方法。
假设我们有类似的东西
char ch;
我们取地址:
char *p = &ch;
所以我们有一个指向char. 我们确信它是有效的。但是我们可以把它看作是一个指向一个元素的数组的指针吗?是的,这似乎是合乎逻辑的,但出现了一个有趣的观点:
如果表达式 P 指向数组对象的一个元素,而表达式 Q 指向同一数组对象的最后一个元素,则指针表达式 Q+1 比较大于 P。
如果我们说这个指针可以被认为是一个指向长度为 1 的数组的指针,那么这条标准意味着我们有权期望
assert(p < p + 1);
这实质上意味着任何有效指针都可以增加 1 并获得比前一个更大的数字(没有溢出)。标准能保证这一点吗?
对于 char,有 2 个有趣的地址 0x7FFFFFFF 和 0xFFFFFFFF - 如果 4 字节(对于 8 字节有类似的数字 - 本质不变)指针由带符号类型表示,则它们中的第一个将溢出,并且第二 - 如果未签名。我希望指针是无符号的,并且-1- 一个未使用的保留地址,但标准中可能没有关于此的内容。但是如果你仔细想想,对于其他数据类型,increment 会增加指针类型的大小,而不是增加 1,所以地址会稍微小一些。但同样,数据将不得不影响这些地址之一。