#include <iostream>
#include <vector>
#include <array>
#define Nbodies 3
class Assembly {
public:
// initializing constructor
Assembly(double _dataA)
: data(_dataA), AssA(nullptr), AssB(nullptr) { }
// double argument copy constructor
Assembly(Assembly &A, Assembly&B)
: AssA(&A), AssB(&B) {
data = A.data * B.data;
}
// single argument copy constructor - generates errors once uncommented
/*
Assembly(Assembly &A)
: data(A.data), AssA(&A), AssB(&A) {
// initialize other members of this class here
}
*/
double data;
private:
// these are const pointers to non-const objects of a type Assembly
Assembly *const AssA, *const AssB;
};
int main() {
std::array<double, Nbodies> datas = {1.0, 2.0, 3.0};
// Initilize first branch of the binary tree
std::vector<Assembly> base_assembly;
for (int i = 0; i < Nbodies; i++) {
base_assembly.emplace_back(datas[i]);
}
// Binary tree assembly - MWE (for general case, I'm using nested for loop)
Assembly AssemblyAB = Assembly(base_assembly[0], base_assembly[1]);
Assembly AssemblyC = Assembly(base_assembly[2]);
Assembly AssemblyS = Assembly(AssemblyAB, AssemblyC);
std::cout << AssemblyS.data << std::endl;
return 0;
}
I'm working on a program that generates a binary try recursively. When I have a branch with an odd number of elements, I need to "rewrite" an element to a lower branch. For this, I use a copy constructor since I need to initialize additional members of the class (I'm using the Eigen library, and some operations can not be done as a one-liner in the initialization list).
My problem arose when I defined a singe argument copy constructor. I get the following error:
.../mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/bits/stl_construct.h:75:7: error:
cannot bind non-const lvalue reference of type 'Assembly&' to an rvalue of type 'Assembly'
Why defining a single argument copy constructor generates such an error? Note that in the case of a two-argument copy constructor the are no errors at all.
A typical copy constructor takes const T&
, or in this case const Assembly&
. Since you don't have that, there is no way for standard library containers such as std::vector
to copy your type, which it would need to do if it ever needs to reallocate the array (eg to make it bigger).
However, std::vector<T>
where T
has a noexcept move constructor will use the move constructor instead, thus avoiding the problem of not having a copy constructor.
Thus the following addition allows this to work:
Assembly(Assembly&&) noexcept = default; // generate a noexcept move constructor
Note that this will result in the newly-constructed object also pointing to the same AssA
and AssB
objects.
As a side note, I would recommend renaming those to AsmA
and AsmB
if only to deter snickering.
Edit:
At the very root, the problem is with that single parameter Assembly&
constructor, which is causing the copy constructor to not be implicitly generated. The similarity to the copy constructor is also bad due to being unintuitive. Assembly thing = other;
would actually call the weird Assembly&
constructor when you would expect it to just copy. Thus the best answer to the problem is just to get rid of it.
Option 1: When you want that behavior, just use the 2 parameter constructor and pass the same object twice.
Option 2: Make it a tag constructor:
// the tag type we'll use to select the weird constructor
inline struct same_asm_t {} same_asm; // not sure what version of C++ you're on; if this doesn't work remove inline and define in a cpp file elsewhere
// define this as a tag constructor (take some other "tag" type as a param for overload resolution)
Assembly(Assembly &A, same_asm_t) : data(A.data), AssA(&A), AssB(&A) {}
// use it like this, where other is an instance of Assembly
Assembly thing(other, same_asm);
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.