Saturday, December 27, 2014

Digest for comp.lang.c++@googlegroups.com - 16 updates in 5 topics

JiiPee <no@notvalid.com>: Dec 27 10:36PM

I am trying to make xx (in pair2_derived) to be a reference member
variable so that it refers to "first" in pair2. What should I put as a
type for xx? I first tried T (because it is/will be the type in real
life), but I get "error: expected ';' at end of member declaration". I
tried other ones as well like pair2<T, T>::_T1 but none worked. I am not
very familiar with templates so would need some help here, thanks.
 
template<class _T1, class _T2>
struct pair2
{
_T1 first;
_T2 second;
};
 
template <typename T>
class pair2_derived: public pair2<T, T>
{
public:
T& xx = pair2<T, T>::first; // xx has a wrong type...what should the
type of xx be?
};
 
---
This email has been checked for viruses by Avast antivirus software.
http://www.avast.com
Paavo Helde <myfirstname@osa.pri.ee>: Dec 27 05:17PM -0600

> type for xx? I first tried T (because it is/will be the type in real
> life), but I get "error: expected ';' at end of member declaration". I
> tried other ones as well like pair2<T, T>::_T1 but none worked. I am
not
> _T1 first;
> _T2 second;
> };
 
Identifiers like _T1 are reserved for implementations, it is illegal to
use them in your own code.
 
> {
> public:
> T& xx = pair2<T, T>::first; // xx has a wrong type...what should
the
> type of xx be?
> };
 
template <typename T>
class pair2_derived: public pair2<T, T>
{
public:
T& xx;
pair2_derived(): xx(this->first) {}
};
JiiPee <no@notvalid.com>: Dec 27 11:33PM

On 27/12/2014 23:17, Paavo Helde wrote:
>> };
> Identifiers like _T1 are reserved for implementations, it is illegal to
> use them in your own code.
 
Ok, but that does not seem to be the problem here. Even if I take _ off
from it for example
pair2<T, T>::T1& xx = pair2<T, T>::first;
 
does not work.
"Öö Tiib" <ootiib@hot.ee>: Dec 27 03:34PM -0800

On Sunday, December 28, 2014 12:36:18 AM UTC+2, JiiPee wrote:
> T& xx = pair2<T, T>::first; // xx has a wrong type...what should the
> type of xx be?
> };
 
No compiler nearby but it might be that this works like you want:
 
template <typename T>
class pair2_derived: public pair2<T, T>
{
public:
typedef pair2<T, T> base;
T& xx = base::first;
};
 
int main()
{
pair2_derived<int> x;
x.first = 42;
x.second = 43;
std::cout << "xx is:" << x.xx << std::endl;
return 0;
}
jononanon@googlemail.com: Dec 27 09:57AM -0800

Hi there,
 
I've derived std::vector and std::vector::iterator
.
 
Unfortunately the derived iterator does not work as I would like.
 
///// test.cpp //////////////////////////////////////////////////
 
#include <iostream>
#include <vector>
 
using std::vector;
 
template<typename T>
struct Myvec : public vector<T> {
using vector<T>::vector;
 
class myiterator;
 
myiterator begin1() {return myiterator{static_cast<vector<T>>(*this).begin()}; }
myiterator end1() {return myiterator{static_cast<vector<T>>(*this).end()}; }
const myiterator begin1()const {return myiterator{static_cast<vector<T>>(*this).begin()}; }
const myiterator end1() const {return myiterator{static_cast<vector<T>>(*this).end()}; }
 
};
 
template<typename T>
struct Myvec<T>::myiterator : public vector<T>::iterator{
// CONSTRUCTOR
myiterator(const typename vector<T>::iterator& it) : vector<T>::iterator{it} {}
using vector<T>::iterator::iterator;
};
 
 
int main()
{
Myvec<int> vec = {1, 2, 3};
for (Myvec<int>::myiterator it = vec.begin1(); it != vec.end1(); ++it) {
std::cout << *it << '\n';
}
return 0;
}
 
///////////////////////////////////////////////////////
 
 
Compile (on linux) with
c++ -std=c++11 -o test test.cpp
 
EXPECTED ("wanted") OUTPUT:
1
2
3
 
The OUTPUT I unfortunately get:
0
0
3
 
What's wrong with the code?
How does one get it working so that the derived iterator is usable (in the way I want)
 
Thanks.
jononanon@googlemail.com: Dec 27 10:17AM -0800

OK, here's how to SOLVE it:
 
Instead of
static_cast<vector<T>>(*this).begin()
USE THIS:
static_cast<vector<T>*>(this)->begin()
 
But the more important question: why does only the 2nd one work correctly???
 
Thanks for any help and pointers ;) on this!!
 
J.
 
 
 
 
Below is the full code:
///////////////////////////////////////////////////////
 
#include <iostream>
#include <vector>
 
using std::vector;
 
template<typename T>
struct Myvec : public vector<T> {
using vector<T>::vector;
 
class myiterator;
 
myiterator begin1() {return myiterator{static_cast<vector<T>*>(this)->begin()}; }
myiterator end1() {return myiterator{static_cast<vector<T>*>(this)->end()}; }
const myiterator begin1()const {return myiterator{static_cast<vector<T>*>(this)->begin()}; }
const myiterator end1() const {return myiterator{static_cast<vector<T>*>(this)->end()}; }
 
};
 
template<typename T>
struct Myvec<T>::myiterator : public vector<T>::iterator{
// CONSTRUCTOR
myiterator(const typename vector<T>::iterator& it) : vector<T>::iterator{it} {}
using vector<T>::iterator::iterator;
};
 
 
int main()
{
Myvec<int> vec = {1, 2, 3};
for (Myvec<int>::myiterator it = vec.begin1(); it != vec.end1(); ++it) {
std::cout << *it << '\n';
}
 
return 0;
}
 
///////////////////////////////////////////////////////
Victor Bazarov <v.bazarov@comcast.invalid>: Dec 27 03:10PM -0500


> But the more important question: why does only the 2nd one work correctly???
 
> Thanks for any help and pointers ;) on this!!
 
> J.
 
The first expression creates a temporary vector<T>, which disappears as
soon as the full expression has been evaluated. The second expression
does not create a temporary and instead yields an iterator for the
existing ('this') vector. The second one works correctly most likely
because you actually need the iterator for the existing vector and not
for some temporary (which becomes invalid as soon as the temporary is
destroyed, BTW).
 
V
--
I do not respond to top-posted replies, please don't ask
Paavo Helde <myfirstname@osa.pri.ee>: Dec 27 03:19PM -0600

jononanon@googlemail.com wrote in
> static_cast<vector<T>*>(this)->begin()
 
> But the more important question: why does only the 2nd one work
> correctly???
 
As Victor explained, the first one makes a copy. To avoid the copy, one
can also cast to a reference:
 
static_cast<vector<T>&>(*this).begin()
 
That said, std::vector (and other STL containers) are not really meant
for derivation. If you want to build on top of them, use them as data
members, not as bases. This will work out better in long term (short
rationale: public derivation leaks out the inner guts of std::vector,
which will overcomplicate your class' interface and make it hard to
maintain its class invariants).
 
Cheers
Paavo
jononanon@googlemail.com: Dec 27 01:21PM -0800

On Saturday, December 27, 2014 9:10:41 PM UTC+1, Victor Bazarov wrote:
> because you actually need the iterator for the existing vector and not
> for some temporary (which becomes invalid as soon as the temporary is
> destroyed, BTW).
 
Oh yes, I think you're right! The first version....
static_cast<vector<T>>(*this) goes ahead and actually USES A COPY CONSTRUCTOR to create a temporary copy of the vector; and then calls begin() to return an iterator for this temporary. Definitely not what I wanted.
 
I need an iterator to the initial vector, therefore using a pointer and deref via -> is what is needed.
jononanon@googlemail.com: Dec 27 01:28PM -0800

On Saturday, December 27, 2014 10:19:29 PM UTC+1, Paavo Helde wrote:
> static_cast<vector<T>&>(*this).begin()
 
Ah yes, thank!
 
> rationale: public derivation leaks out the inner guts of std::vector,
> which will overcomplicate your class' interface and make it hard to
> maintain its class invariants).
 
This makes sense. Because as it happens, I'm working with a derived vector, that handles pointers and automatically deletes them in the destructor. And "SURPRISE": I have to also overload 'erase' to also do deletes! And other stuff as well... probably. Which is exactly what you say in the rationale.
 
Thanks.
"Jens Müller" <ich@tessarakt.de>: Dec 27 11:27PM +0100

> Because as it happens, I'm working with a derived vector, that handles pointers and automatically deletes them in the destructor. And "SURPRISE": I have to also overload 'erase' to also do deletes! And other stuff as well... probably. Which is exactly what you say in the rationale.
 
Then a better solution is probably to use a normal std::vector and put
suitable smart pointers (e.g. std::unique_ptr) into it.
jononanon@googlemail.com: Dec 27 03:05PM -0800

On Saturday, December 27, 2014 11:27:32 PM UTC+1, Jens Müller wrote:
> > Because as it happens, I'm working with a derived vector, that handles pointers and automatically deletes them in the destructor. And "SURPRISE": I have to also overload 'erase' to also do deletes! And other stuff as well... probably. Which is exactly what you say in the rationale.
 
> Then a better solution is probably to use a normal std::vector and put
> suitable smart pointers (e.g. std::unique_ptr) into it.
 
Challange: try that suggestion of yours using std::unique_ptr
;)
 
 
Here's a solution (no peeking!):
 
 
///////////////////////////////////////
 
#include <vector>
#include <memory>
#include <initializer_list>
 
 
using std::vector;
 
template<typename T>
struct pvector : public vector<std::unique_ptr<T>>{
// using vector<std::unique_ptr<T>>::vector;
pvector(std::initializer_list<T*> lst);
 
void push_back(T *p) { static_cast<vector<std::unique_ptr<T>> *>(this)->push_back(std::unique_ptr<T>{p}); }
};
 
template<typename T>
pvector<T>::pvector(std::initializer_list<T*> lst) {
for (T* p: lst) {
push_back(p);
}
}
 
///////////////////////////////////////
 
Yip, what makes this interesting is the fact that std::unique_ptr cannot be copied (in order to prevent double frees!)
Paavo Helde <myfirstname@osa.pri.ee>: Dec 27 05:11PM -0600

jononanon@googlemail.com wrote in
 
> using std::vector;
 
> template<typename T>
> struct pvector : public vector<std::unique_ptr<T>>{
 
I think you did not get the idea, which was to just use std::vector of a
suitable element type, not to derive from it.
 
typedef vector<std::unique_ptr<mytype>> pvector;
 
If std::unique_ptr does not work for you by some reason, consider
std::shared_ptr.
 
Cheers
Paavo
ich@tessarakt.de: Dec 27 10:28PM

This message was cancelled from within Mozilla Thunderbird.
jononanon@googlemail.com: Dec 27 10:01AM -0800

Hi there,
 
Im deriving from std::vector and std::vector::iterator.
 
/////////// test.cpp ///////////////////////////////
#include <iostream>
#include <vector>
 
using std::vector;
 
template<typename T>
struct Myvec : public vector<T> {
using vector<T>::vector;
 
class myiterator;
 
myiterator begin1() {return myiterator{static_cast<vector<T>>(*this).begin()}; }
myiterator end1() {return myiterator{static_cast<vector<T>>(*this).end()}; }
const myiterator begin1()const {return myiterator{static_cast<vector<T>>(*this).begin()}; }
const myiterator end1() const {return myiterator{static_cast<vector<T>>(*this).end()}; }
 
};
 
template<typename T>
struct Myvec<T>::myiterator : public vector<T>::iterator{
// CONSTRUCTOR
myiterator(const typename vector<T>::iterator& it) : vector<T>::iterator{it} {}
using vector<T>::iterator::iterator;
};
 
 
int main()
{
Myvec<int> vec = {1, 2, 3};
for (Myvec<int>::myiterator it = vec.begin1(); it != vec.end1(); ++it) {
std::cout << *it << '\n';
}
return 0;
}
///////////////////////////////////////////////
 
Compile (on linux) with:
c++ -std=c++11 -o test test.cpp
 
EXPECTED OUTPUT:
1
2
3
 
REAL OUTPUT is unfortunately:
0
0
3
 
How can one fix the code?
How does one properly derive an iterator and get it working?
 
Thanks.
Jack Chuge <zhuge.jack@gmail.com>: Dec 27 07:54PM +0800

Martijn Lievaart 於 2014-12-4 3:47 寫道:
>> be in live code.
 
> Yeah, ++++i feels like some other unspecified computer language. :-)
 
> M4
 
Martin, I agree with you, lol
 
--
Jack
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: