Topic: request: std::vector with typed indices
Author: derek@antiquark.com
Date: Wed, 13 Sep 2006 13:49:56 CST Raw View
Hello All,
In my job, I frequently have to implement proprietary comms protocols
that interact with legacy devices or systems.
Typically, I use a std::vector<char> to organize my communication
packets. I use the push_back function to fill a vector with raw bytes
from a communication source, like a serial port, then I access the
elements of the vector with the "[]" or ".at()" functions for further
processing.
The indices that describe the internal organization of a packet are
often specified as "#defines" or "const ints," but if I'm processing
various types of packets, I need different lists of indices. That
always leaves me worried that I (or some future developer) will use the
wrong index for a particular packet type.
I'm wondering if anyone else thinks it would be a good idea to add
another template parameter to the std::vector class, which specifies
the type of argument passed to the "[]" operator or ".at()" function.
This would help ensure that proper indices are used for a certain
vector types.
Below is some code that demonstrates how this style of vector might be
used.
enum EFooPacketIndices
{
fpHeaderIx = 0,
fpTypeIx = 1,
fpBlahIx = 12
}
enum FBarPacketIndices
{
bpHeaderIx = 1,
bpTypeIx = 2,
bpBlahIx = 10
}
int main()
{
vector<char, allocator<char>, EFooPacketIndices> foo_packet(123);
vector<char, allocator<char>, EBarPacketIndices> bar_packet(123);
foo_packet[1] = 'a'; // compiler error
foo_packet[EFooPacketIndices(1)] = 'a'; // no warning
foo_packet[EBarPacketIndices(1)] = 'a'; // compiler error
foo_packet[fpHeaderIx] = 'a'; // OK
foo_packet[bpHeaderIx] = 'a'; // compiler error
}
--
Thanks,
Derek Ross
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: v.Abazarov@comAcast.net ("Victor Bazarov")
Date: Wed, 13 Sep 2006 19:52:24 GMT Raw View
derek@antiquark.com wrote:
> In my job, I frequently have to implement proprietary comms protocols
> that interact with legacy devices or systems.
>
> Typically, I use a std::vector<char> to organize my communication
> packets. I use the push_back function to fill a vector with raw bytes
> from a communication source, like a serial port, then I access the
> elements of the vector with the "[]" or ".at()" functions for further
> processing.
>
> The indices that describe the internal organization of a packet are
> often specified as "#defines" or "const ints," but if I'm processing
> various types of packets, I need different lists of indices. That
> always leaves me worried that I (or some future developer) will use
> the wrong index for a particular packet type.
>
> I'm wondering if anyone else thinks it would be a good idea to add
> another template parameter to the std::vector class, which specifies
> the type of argument passed to the "[]" operator or ".at()" function.
> This would help ensure that proper indices are used for a certain
> vector types.
>
> Below is some code that demonstrates how this style of vector might be
> used.
>
> enum EFooPacketIndices
> {
> fpHeaderIx = 0,
> fpTypeIx = 1,
> fpBlahIx = 12
> }
>
> enum FBarPacketIndices
> {
> bpHeaderIx = 1,
> bpTypeIx = 2,
> bpBlahIx = 10
> }
>
> int main()
> {
> vector<char, allocator<char>, EFooPacketIndices> foo_packet(123);
> vector<char, allocator<char>, EBarPacketIndices> bar_packet(123);
>
> foo_packet[1] = 'a'; // compiler error
> foo_packet[EFooPacketIndices(1)] = 'a'; // no warning
> foo_packet[EBarPacketIndices(1)] = 'a'; // compiler error
> foo_packet[fpHeaderIx] = 'a'; // OK
> foo_packet[bpHeaderIx] = 'a'; // compiler error
> }
Wouldn't you rather have your own class template derived from 'vector'
and providing its own operator[] for that? At the first glance it
does not seem like an overly complex task to implement such template;
and as such it probably isn't needed in the standard library, but might
come in handy, so a published implementation of an adapter (that's
what it probably looks like) is useful.
V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: brangdon@cix.co.uk (Dave Harris)
Date: Wed, 13 Sep 2006 21:41:01 GMT Raw View
derek@antiquark.com () wrote (abridged):
> I'm wondering if anyone else thinks it would be a good idea to add
> another template parameter to the std::vector class, which specifies
> the type of argument passed to the "[]" operator or ".at()" function.
> This would help ensure that proper indices are used for a certain
> vector types.
I have a similar template class. Mine is based on fixed-sized C-arrays,
though - the use of enum indexes kinda implies the array has a fixed
maximum size, and I don't need push_back to keep track when the array is
being written to.
If it is to be added I think it should be a wrapper class rather than
another parameter to std::vector, so that it could be used with the TR1
fixed-size array.
It's easy enough to write by hand, so perhaps it isn't really needed in
the standard. Then again, it's good to promote type-safe indexes, so it
could be added for ideological reasons. Have you proposed it to Boost?
-- Dave Harris, Nottingham, UK.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: derek@antiquark.com
Date: Wed, 13 Sep 2006 18:07:30 CST Raw View
"Victor Bazarov" wrote:
> Wouldn't you rather have your own class template derived from 'vector'
> and providing its own operator[] for that? At the first glance it
> does not seem like an overly complex task to implement such template;
> and as such it probably isn't needed in the standard library, but might
> come in handy, so a published implementation of an adapter (that's
> what it probably looks like) is useful.
Thanks for the comment, that idea seems to work well. (See code below.
Allocators have been ignored.)
Derek.
=====
#include <vector>
#include <iostream>
template<class T, class IndexType = size_t>
class vector_typed_index : public std::vector<T>
{
public:
typedef IndexType index_type;
typedef typename std::vector<T>::size_type size_type;
T& operator[](const index_type& index)
{
return std::vector<T>::operator[](size_type(index));
}
const T& operator[](const index_type& index) const
{
return std::vector<T>::operator[](size_type(index));
}
T& at(const index_type& index)
{
return std::vector<T>::at(size_type(index));
}
const T& at(const index_type& index) const
{
return std::vector<T>::at(size_type(index));
}
explicit vector_typed_index()
:std::vector<T>()
{}
explicit vector_typed_index(size_type n, const T& v = T())
:std::vector<T>(n, v)
{}
vector_typed_index(const vector_typed_index& x)
:std::vector<T>(x)
{}
template<class InIt> vector_typed_index(InIt first, InIt last)
:std::vector<T>(first, last)
{}
};
enum ERxPacketIndices
{
rxHeaderIx = 0, rxSizeIx = 1
};
enum ETxPacketIndices
{
txHeaderIx = 1, txSizeIx = 2
};
int main()
{
vector_typed_index<int, ERxPacketIndices> v1(size_t(5), 123);
vector_typed_index<int, ERxPacketIndices> v1b(size_t(5), 333);
vector_typed_index<int, unsigned char> v2;
vector_typed_index<int, ETxPacketIndices> v3;
vector_typed_index<int> v4;
v1.push_back(11);
v1.push_back(22);
v1.push_back(33);
for(int i = 0 ; i < 1000; i++)v2.push_back(i);
std::cout << v1[rxHeaderIx] << std::endl;
std::cout << v1[ERxPacketIndices(2)] << std::endl;
//std::cout << v1[0] << std::endl; //compiler error.
//std::cout << v1[txHeaderIx] << std::endl; // compiler error.
std::cout << v2[256] << std::endl; // prints 0, because index rolls
over at 256.
std::cout << (v1 == v3) << std::endl;
v4.push_back(234);
std::cout << v4[0] << std::endl;
v1 = v1b;
}
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: derek@antiquark.com
Date: Wed, 13 Sep 2006 19:10:20 CST Raw View
Dave Harris wrote:
> If it is to be added I think it should be a wrapper class rather than
> another parameter to std::vector, so that it could be used with the TR1
> fixed-size array.
> It's easy enough to write by hand, so perhaps it isn't really needed in
> the standard. Then again, it's good to promote type-safe indexes, so it
> could be added for ideological reasons. Have you proposed it to Boost?
Along with tr1::array, there could also be wrappers for:
bitset
deque
valarray
maybe basic_string (which doesn't really make sense.)
I'll post a message in the boost forum asking if there's a need for
such a set of wrappers.
Derek.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: "ben.craig@gmail.com" <ben.craig@gmail.com>
Date: Thu, 14 Sep 2006 12:18:12 CST Raw View
> template<class T, class IndexType = size_t>
> class vector_typed_index : public std::vector<T>
Since you are using public inheritance, there are still operator[]s and
at()s taking size_t parameters. This is probably not what you want
since it circumvents the strong typing you are trying to implement.
What you probably want is private inheritance and lots of "using"
statements, or containment and lots of forwarding functions.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: petebecker@acm.org (Pete Becker)
Date: Thu, 14 Sep 2006 17:51:29 GMT Raw View
ben.craig@gmail.com wrote:
>> template<class T, class IndexType = size_t>
>> class vector_typed_index : public std::vector<T>
>
> Since you are using public inheritance, there are still operator[]s and
> at()s taking size_t parameters. This is probably not what you want
> since it circumvents the strong typing you are trying to implement.
You won't get them accidentally. Try it.
--
-- Pete
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." For more information about this book, see
www.petebecker.com/tr1book.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: brangdon@cix.co.uk (Dave Harris)
Date: Thu, 14 Sep 2006 13:28:52 CST Raw View
derek@antiquark.com () wrote (abridged):
> I'll post a message in the boost forum asking if there's a need for
> such a set of wrappers.
Ideally there would only be one wrapper, not a set of them. As with
std::stack.
-- Dave Harris, Nottingham, UK.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: "ben.craig@gmail.com" <ben.craig@gmail.com>
Date: Thu, 14 Sep 2006 13:42:04 CST Raw View
Pete Becker wrote:
> ben.craig@gmail.com wrote:
> >> template<class T, class IndexType = size_t>
> >> class vector_typed_index : public std::vector<T>
> >
> > Since you are using public inheritance, there are still operator[]s and
> > at()s taking size_t parameters. This is probably not what you want
> > since it circumvents the strong typing you are trying to implement.
>
> You won't get them accidentally. Try it.
Ahh, I had forgotten that the overloaded operator[] would hide the base
class's operator[], so it does indeed prevent unwanted size_t
parameters. However, I stand by my original recommendation.
vector_typed_index no longer models Liskov IS-A or WORKS-LIKE-A (Herb
Sutter's Exceptional C++: Item 22 discusses this issue).
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Pete Becker <petebecker@acm.org>
Date: Thu, 14 Sep 2006 16:05:12 CST Raw View
ben.craig@gmail.com wrote:
>
> Ahh, I had forgotten that the overloaded operator[] would hide the base
> class's operator[], so it does indeed prevent unwanted size_t
> parameters. However, I stand by my original recommendation.
> vector_typed_index no longer models Liskov IS-A or WORKS-LIKE-A (Herb
> Sutter's Exceptional C++: Item 22 discusses this issue).
>
Which only means that you might not be able to use vector_typed where
you can use vector. So don't do that. Template code rarely follows
guidelines developed for inheritance and virtual functions. On the other
hand, if you've written, for example, a template function that takes a
vector and displays its contents in some fancy format, you probably do
what to be able to use it, unchanged, with vector_typed.
--
-- Pete
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." For more information about this book, see
www.petebecker.com/tr1book.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]