#include <iostream>
#include <vector>
using namespace std;
void testfn(double* v1, double *v2, double *v3, int n);//I must use this function
class CLS{
private:
vector<double> v;
public:
CLS(vector<double> vin);
CLS operator+(CLS & A);
CLS operator*(CLS & A);
};
CLS::CLS(vector<double> vin)
{
v=vin;
}
CLS CLS::operator*(CLS &A){
//assuming the two vectors have the same length
vector<double> vtmp(v.size(),0);
testfn(&*A.v.begin(),&*v.begin(),&*vtmp.begin(),(int)A.v.size());
CLS C(vtmp);
return C;
}
CLS CLS::operator+(CLS &A){
//assuming the two vectors have the same length
vector<double> vtmp(v.size(),0);
testfn(&*A.v.begin(),&*v.begin(),&*vtmp.begin(),(int)A.v.size());
CLS C(vtmp);
return C;
}
void testfn(double* v1, double *v2, double *v3, int n)
{
for (int i=0;i<n;i++)
{
*v3=*v1+*v2;
++v1;
++v2;
++v3;
}
}
int main(){
vector<double> v1(100,1.0), v2(100,2.0), v3(100,0.0);
CLS C1(v1),C2(v2),C3(v3);
CLS C4=C1*(C1+(C2*C3+C2))*C1*C2*C3+C1+C2+C3;
return 0;
}
我创建了CLS类并定义了两个运算符+和*。我想使用这些运算符就像我们如何使用+和*来表示整数和双精度。因此,我在主CLS C4=C1*(C1+(C2*C3+C2))*C1*C2*C3+C1+C2+C3;
中有一个测试行。但是,在使用gcc编译此代码时,我遇到了大量错误。我对运算符重载的规则不够熟悉。我应该如何修改*和+的定义(可能只是参数?),以便CLS C4=C1*(C1+(C2*C3+C2))*C1*C2*C3+C1+C2+C3;
有效?
补充:我不知道如何对operator +和*使用const参数,因为这两个运算符的定义涉及另一个函数testfn
,其参数是double *而不是const double *。此外,我不想更改testfn
定义中的任何部分,因为在我的实际代码中它对应于LAPACK中的一个函数,我绝对无权更改。
答案 0 :(得分:1)
最好将case class CsvFile(lines: Map[String, List[String]], rowCount: Int = 0) {
def merge(line: Map[String, String]): CsvFile = {
val orig = lines.withDefaultValue(List.fill(rowCount)(""))
val current = line.withDefaultValue("")
val newLines = (lines.keySet ++ line.keySet) map {
k => (k, orig(k) :+ current(k))
}
CsvFile(newLines.toMap, rowCount + 1)
}
}
和operator+
定义为友元函数,这样如果存在从其他类型到operator*
的隐式转换,则可以使用运算符。如果它是一个成员函数,那么如果第一个操作数不是CLS
,则不会找到它。
CLS
答案 1 :(得分:1)
你应该在你的代码中使用空格,阅读起来很糟糕。不要对类型名和变量使用大写字母,这也很难阅读。
这不是必需的,而是一个小优化,通过引用传递构造函数参数,然后在构造函数初始化列表中初始化v
成员(而不是通过在正文中分配它):
CLS::CLS(const vector<double>& vin) : v(vin)
{
}
我会添加一个新的构造函数,它会获得所需的大小,并立即将v
成员的大小调整为,这样可以使代码更简单:
CLS::CLS(int n) : v(n, 0)
{
}
首先将const
添加到函数参数和成员函数本身:
CLS CLS::operator*(const CLS& a) const {
^^^^^ ^^^^^
然后默认为结果构造一个空的C
对象,并使用所需大小的向量成员:
//assuming the two vectors have the same length
CLS result(v.size());
如果您创建数据向量的副本并处理这些副本,那么您可以使成员函数及其参数为const:
vector<double> v1 = a.v;
vector<double> v2 = v;
现在你可以获得那些向量中的数据的非常量指针,你可以直接将输出写入C.v
而不是写入vtmp
,然后将其复制到返回的对象中: / p>
testfn(&*v1.begin(), &*v2.begin(), &*result.v.begin(), v.size());
最后返回结果:
return result;
}
其他功能完全相同:
CLS CLS::operator+(const CLS& a) const {
//assuming the two vectors have the same length
CLS result(v.size());
vector<double> v1 = a.v;
vector<double> v2 = v;
testfn(&*v1.begin(), &*v2.begin(), &*result.v.begin(), v.size());
return result;
}
现在这将能够接受const参数,因此应该使用由每个C1+C2
或C3*C4
表达式创建的临时对象。
由于数据的额外副本,代码的效率稍差,但构造函数中的优化有助于此。如果你能够使用C ++ 11,那么即使那些效率低下也可以解决,但需要做更多的工作。
首先,C ++ 11提供vector<T>::data()
来获取指针,这比&*v.begin()
更清晰。 (它不是C ++ 11之前的C ++标准的一部分,但GCC甚至为C ++ 98提供了它)。您可以更改上面显示的代码,使用v.data()
代替&*v.begin()
,如下所示。
在C ++ 11中,您可以通过将(非常量)右值引用绑定到临时对象来添加对临时对象起作用的其他重载。因为rvalue引用允许您对临时对象进行非const访问,所以您不需要复制其数据来获取非常量指针,并且可以直接使用它们。除了上面显示的原始重载之外,还要添加这些运算符重载:
CLS CLS::operator+(CLS&& a) && {
//assuming the two vectors have the same length
CLS result(v.size());
testfn(a.v.data(), v.data(), result.v.data(), v.size());
return result;
}
CLS CLS::operator*(CLS&& a) && {
//assuming the two vectors have the same length
CLS result(v.size());
testfn(a.v.data(), v.data(), result.v.data(), v.size());
return result;
}
这可以避免在算术表达式创建的中间临时对象中创建任何副本。我还发现很多更容易理解和更容易阅读。
完整的工作示例位于http://coliru.stacked-crooked.com/a/6e40d20eb7f1e9fc
答案 2 :(得分:1)
使用testfn
所有params非const的不寻常要求有点奇怪,但是......嗯.. 不情愿地接受不可接受的情况复杂表达式 - testfn的前两个参数需要const double*
。
基本原理: C ++标准要求临时工具绑定到const references
- 某些interesting details here
@Resorter说:
&#34;感谢您告诉我,我想学习。但你确定它解决了我的问题吗?我真的想先解决这个问题。&#34;
[其中它是&#39;移动构造函数&#39;和&#39;移动作业&#39;]
以下&#34; fish&#34;假设您已经阅读/学习了捕鱼move constructor和move assign以及rules of 5/3/0,
补充学习材料:copy elision - 允许编译器跳过复制/移动构造函数,即使它们会产生副作用。
// some implementations
void testfn0(const double* v1, const double *v2, double *v3, int n) {
for(int i=0; i<n; i++) {
v3[i]=v1[i]+v2[i];
}
}
void testfn1(double* v1, double *v2, double *v3, int n) {
for(int i=0; i<n; i++) {
v3[i]=v1[i]*v2[i];
}
}
class CLS {
std::vector<double> v;
public:
// constructor taking a const reference
CLS(const std::vector<double>& in) : v(in) {
std::cout << "copy vec" << std::endl;
}
// extra constructor with rvalue reference: it will "canibalize" the parameter
CLS(std::vector<double>&& in) : v(in) {
std::cout << "move vec" << std::endl;
}
// Rule of 5 applied
// Copy constructor
CLS(const CLS& other) : v(other.v) {
std::cout << "copy CLS" << std::endl;
}
// Move constructor
CLS(CLS&& other) : v(std::move(other.v)) {
std::cout << "move CLS" << std::endl;
}
~CLS() { }
// Copy assgn
CLS& operator=(const CLS& o) {
this->v=o.v;
std::cout << "assgn CLS" << std::endl;
return *this;
}
// Move assgn
CLS& operator=(CLS&& other) {
this->v=std::move(other.v);
std::cout << "move CLS" << std::endl;
return *this;
}
// WILL NOT WORK WITHOUT const FOR COMPLEX EXPRESSIONS
// |
// ----------
// V
CLS operator+(const CLS& rhs) {
std::vector<double> vtmp(v.size(),0);
testfn0(&*rhs.v.begin(),&*v.begin(),&*vtmp.begin(),(int)rhs.v.size());
CLS ret(std::move(vtmp));
return ret;
}
// WILL NOT WORK WITHOUT const FOR COMPLEX EXPRESSIONS
// |
// ----------
// V
CLS operator*(const CLS& rhs) {
std::vector<double> vtmp(v.size(),0);
testfn1(&*rhs.v.begin(),&*v.begin(),&*vtmp.begin(),(int)rhs.v.size());
CLS ret(std::move(vtmp));
return ret;
}
};
int main() {
std::cout << "\n--- inits " << std::endl;
CLS a(std::vector<double>{1,2,3}); // move vec
CLS b(std::vector<double>{3,2,1}); // move vec
std::cout << "\n--- add " << std::endl;
CLS c=a+b; // move vec and 'silence' (copy elision)
std::cout << "\n--- mul " << std::endl;
CLS d=a*b; // move vec and 'silence' (copy elision)
std::cout << "\n--- copy " << std::endl;
CLS m=c; // Copy CLS - constructor
std::cout << "\n--- move " << std::endl;
CLS n=std::move(d); // Move CLS - constructor
std::cout << "\n--- assgn (d=c) and copy (x=c)" << std::endl;
CLS x=d=c;
}