Home » U++ Library support » U++ Core » Fixes to Array::Create & Vector::Create
Fixes to Array::Create & Vector::Create [message #49076] |
Fri, 15 December 2017 03:46 |
Novo
Messages: 1371 Registered: December 2006
|
Ultimate Contributor |
|
|
Hi Mirek,
Could you please change methods Array::Create & Vector::Create to make them look like below?
template<class TT, class... Args>
TT& Create(Args&&... args) { TT *q = new TT(pick(args)...); Add(q); return *q; }
template <class... Args>
T& Create(Args&&... args) { if(items >= alloc) GrowF(); return *(::new(Rdd()) T(pick(args)...)); }
This shouldn't break anything, and as a bonus this should allow to pass arguments by reference in case they do not have a copy constructor, what is quite common with Upp.
Regards,
Regards,
Novo
|
|
|
|
|
Re: Fixes to Array::Create & Vector::Create [message #49079 is a reply to message #49078] |
Fri, 15 December 2017 09:44 |
|
mirek
Messages: 14039 Registered: November 2005
|
Ultimate Member |
|
|
Unfortunately, this seems not to work:
struct Test {
Vector<int> a;
int b;
Test(Vector<int>&& a, int b) : a(pick(a)), b(b) {}
};
CONSOLE_APP_MAIN
{
Array<Test> h;
Vector<int> v;
v.Add(12);
h.Create<Test>(v, 22);
DDUMP(v.GetCount());
h.Create<Test>(pick(v), 22);
DDUMP(v.GetCount());
}
Here, I would expect const Args& for the first 'Create' and && for the second one.
For some reason, both end in && overload (I am really not sure why, IMO they should not, but they do with both MSC and GCC).
So unfortunately, to stay safe, I am going to rollback this feature. This has really trivial workaround (default constructor + Set method).
Mirek
|
|
|
Re: Fixes to Array::Create & Vector::Create [message #49083 is a reply to message #49079] |
Fri, 15 December 2017 17:40 |
Novo
Messages: 1371 Registered: December 2006
|
Ultimate Contributor |
|
|
Sorry, my bad. The code should look like below.
template<class TT, class... Args>
TT& Create(Args&&... args) { TT *q = new TT(std::forward<Args>(args)...); Add(q); return *q; }
struct Test {
Test(const Vector<int>& a, int b) : a(a, 0), b(b) {}
Test(Vector<int>&& a, int b) : a(pick(a)), b(b) {}
Vector<int> a;
int b;
};
CONSOLE_APP_MAIN
{
Array<Test> h;
Vector<int> v;
v.Add(12);
// Copy-constructor
h.Create<Test>(v, 22);
DDUMP(v.GetCount());
// Move-constructor
h.Create<Test>(pick(v), 22);
DDUMP(v.GetCount());
v.Add(21);
h.Create<Test>(Vector<int>(v, 0), 22);
DDUMP(v.GetCount());
}
I recompiled TheIDE with this change and it works perfectly for me.
How it works.
type&& is called a universal/perfect/forwarding reference and it can be ether type&& or type& depending on arguments. This is why your method Create(const Args&... args) was redundant. Create(Args&&... args) is a better match.
The problem was that I was using pick, which unconditionally converts type to an rvalue, instead of std::forward, which preservers type (an lvalue will stay the lvalue).
Regards,
Novo
[Updated on: Fri, 15 December 2017 18:21] Report message to a moderator
|
|
|
|
|
Goto Forum:
Current Time: Sat Sep 21 06:17:08 CEST 2024
Total time taken to generate the page: 0.03689 seconds
|