Can I get a const slice_array from a const valarray? - c++

I have a function that accepts a const reference to a valarray, and I want to be able to slice the array and pass the slice into another function that expects a const slice_array. I know that I can just use operator[] and a slice to get a new, copied valarray out of the original valarray, but I want to avoid the copy. Everything is const, so I feel like that should be okay. However, the documentation for the subscript operator for valarray ONLY returns a slice_array objects when applied to non-const valarrays. This feels kind of a major deficiency in the valarray class. Am I missing something? How do I get a slice of a const valarray without incurring a copy?
Here is an example of what I'm talking about:
void foo( const valarray<double> &big_stuff )
{
const slice_array<double> small_stuff = big_stuff[slice(start, size, stride)];
bar( small_stuff );
}
Thanks!

How do I get a slice of a const valarray without incurring a copy?
There is no way to do this, because of std::valarray not contain std::slice_array
for any request, so it cat not give you just link(pointer,reference) to std::slice_array that you request.
But std::slice_array can contains only three machine words,
hard to imagine situation where not copy of std::slice_array can optimize something. For example from gcc/libstdc++ (only data, functions stripped):
template<typename _Tp>
class slice_array {
const size_t _M_sz;
const size_t _M_stride;
const _Array<_Tp> _M_array;
};
where _Array:
template<typename _Tp>
struct _Array { _Tp* const __restrict__ _M_data; };

Related

Calling count method of std::set of pointers with const key type reference

I have a class like
struct S {
bool foo(const AType& v) const {
return values.count(&v); // compile error due to the constness of v
}
private:
std::set<AType*> values;
};
This is a simplified version. In real code, foo does some complex things.
The code produces an error
invalid conversion from ‘const AType*’ to ‘std::set<AType*>::key_type {aka AType*}’
I think foo should take 'const AType& v' because it does not mutate v.
The type of the member variable 'values' can not be std::set<const AType*> because some methods of the struct S call non-const methods of the elements contained in 'values'.
I can cast constness of 'v' away:
bool foo(const AType& v) const {
return values.count((AType*) &v);
}
But I think this may not be a good solution in general.
What solution could I have?
template<class T>
struct const_ptr_compare:std::less<T const*> {
typedef void is_transparent;
};
std::set<AType*, const_ptr_compare<AType>> values;
and bob is your uncle.
I defined a comparator that can transparently handle T const* comparisons as well as T* comparisons. I then told std::set that it is transparent.
The is_transparent technique is a C++14 enhancement to std::set. Your compiler may already have support for it.
If you want to be able to pass in base-classes-of-T a bit more work needs to be done. You need a function object that tests its two arguments (each pointers to const) to see which is a base class of the other, and does a std::less<base const*>{}(lhs, rhs) using that base class. However, that is going further down the rabbit hole than we need to.
A C++11/03 approach could involve making the editable portions of AType mutable, and having a const AType* set. Failing that, a const_cast<AType*> is reasonable.
Please don't use a C-style cast: they are almost never required, and they can be accidentally too powerful.
The root of the problem is this:
The type of the member variable 'values' can not be std::set because some methods of the struct S call non-const methods of
the elements contained in 'values'.
You are not supposed to mutate the set key in any way.
You should be using a map, where the actual key parts are in the key and are const, and the mutating parts are in the value and are non-const.
If this is impractical for your design, I understand. The const_cast workaround will solve the issue. It feels inelegant, but that's because your usage of set is inelegant.
This is just one of the many problems of the const correctness concept: it doesn't scale by composition.
The casting solution is just ok, if you feel it's "dirty" in some way probably you're overestimating cleanness of the const concept.
Consider that defining special types for const_iterator and const_reverse_iterator was needed or that sometimes const correctness requires actual code duplication (e.g. in many cases for operator[]) or that if you've an object containing a non-const pointer you can mutate the pointed-to object freely and even delete it in const members.
Your cast doesn't look that bad in comparison :-)

Is there a way to make these closely-related types interoperable?

I have a template class for treating data stored elsewhere as a 2-D image.
template <typename Pixel>
class ImageWin {
...
};
It has iterators for read/write access to the underlying image and const_iterators for read-only access, and as you would expect, const methods return const iterators and non-const methods return non-const iterators. If the Pixel type is const, then all of the iterators are const iterators.
This makes ImageWin<const int> and const ImageWin<int> very similar types. They both have the same set of iterators (const iterators). Neither one can modify the underlying pixels. The only difference is that ImageWin<const int> can be made to point somewhere else (i.e., where the window points to is mutable, but the pixels are not).
If I have a function that needs read access to the pixel data, I would like to be able to declare something like:
void needs_read_only( const ImageWin<int>& image );
The question is, is there any way to pass ImageWin<const int> into it? I could certainly make it a template function, but I'm trying to avoid that if possible. I was thinking that I could make const ImageWin<Pixel> implicitly convertible to ImageWin<const Pixel>, but I actually want the reverse since a const ImageWin is more restrictive than an ImageWin of const pixels. In general, I can't make ImageWin<Pixel> convertible to ImageWin<const Pixel> because that would violate the const-ness of the pixels if the ImageWin<Pixel> weren't const.
Are there any tricks I'm missing?
Thanks.
Why not simply overload it ?
void needs_read_only( const ImageWin<Pixel>& image ) /* const ??? */;
void needs_read_only( const ImageWin<const Pixel>& image ) /* const ??? */;
Feel free to factor out the logic between two implementations. You can pass any kind of reference to these functions.
As a sidenote, if they are member functions, double-check if the this pointer should be const.

Giving preference to one operator[] over another

Consider the following class:
class Test
{
public:
Test( char );
Test( int );
operator const char*();
int operator[]( unsigned int );
};
When I use it:
Test t;
Test& t2 = t[0];
I get a compiler error where it can't figure out which operator[] to use. MSVC and Gcc both. Different errors. But same problem.
I know what is happening. It can construct a Test from either an int or a char, and it can either use Test::operator[] or it can cast to const char* and use the built char*[].
I'd like it to prefer Test::operator[].
Is there a way to specify a preference like this?
UPDATE: First, I'll agree with response below that there is no language feature that lets you specify a priority for conversions. But like juanchopanza found below - you can create such a preference indirectly by making one conversion require no casts, and make the other require a cast. E.g. unsigned int as the argument for operator[] won't work but, using int will.
The default index argument is unsigned - for gcc and msvc anyway - so making the index argument unsigned will cause the compiler to prefer the right operator.
#Konrad: about implicit conversions to built-in types. Agree generally. But I need it in this case.
No there isn't. And this kind of ambiguity is why automatic conversions to another type (like operator char*) are not recommended.
You can always make the constructors explicit – or, as john has noted, omit the conversion operator. I’d usually recommend doing all of these things but since your code is a toy example it’s hard to say what is appropriate in your situation.
That said, the following should work:
Test const& t2 = t.operator[](0);
(Note the added const – otherwise you’d bind a temporary to non-const reference which doesn’t work either.)
I've implemented container classes like yours before -- it is entirely possible to avoid ambiguity problems while maintaining a clean, intuitive syntax.
First, you need to take const-ness into account. Usually, a const char* cast will not modify the object, so make this a const member function:
operator const char*() const;
Also, your [] operator is returning an int instead of int&, so this should probably be const too:
int operator[]( unsigned int ) const;
If you want to be able to assign a value to an indexed element (mytest[5]=2), you would add another operator function like this (this doesn't replace the const version above -- keep both):
int& operator[](unsigned int);
Next, you will want to accept indexes that are not just unsigned int. A literal integer has the int type. To avoid problems related to index type, you need to overload operator for alternatives. These overloads will just static_cast the index to your native index type and pass it to the native overload (the one for the native index type). One of these overloads might look like:
int operator[]( int idx ) const {
return operator[]( static_cast<unsigned int>(idx) );
}
Instead of adding a bunch of overloads, you could use a single template member function to cover all possibilities. The template function will get used for any index types that do not already have a non-template overload. And this preference for non-template overloads is unambiguous. Essentially, this implements your request for a preferred operator, but const-ness is not templatable, so two versions would be required if you have a const and a non-const [] operator. This catch-all member function might look like this (keep in mind that its definition must stay in your class' declaration and cannot be moved to an implementation file):
template <typename IT>
int operator[]( const IT& idx ) const {
return operator[]( static_cast<unsigned int>(idx) );
}
If you added a non-const version of the [] operator, then you would also need:
template <typename IT>
int& operator[]( const IT& idx ) {
return operator[]( static_cast<unsigned int>(idx) );
}
Enjoy!

Class storing pointers to vector in C++

I'm implementing a class Aviary, which can store pointers to Bird-objects. Now, I have the following:
class Aviary {
public:
const Bird &operator[](const size_t index) const {
return birds[index];
}
Bird &operator[](const size_t index) {
return birds[index];
}
private:
std::vector<Bird*> birds;
The Bird-objects are stored as pointers in order to avoid object-slicing. However, there is a problem with the operator[]-implementation (Reference to type 'const Bird' could not bind to an lvalue of 'const value_type' (aka 'Bird *const')).
How do I implement the operator[] properly?
Since you store pointers, you should dereference the pointer for return reference.
const Bird &operator[](const size_t index) const {
return *birds[index];
}
Bird &operator[](const size_t index) {
return *birds[index];
}
Side note: use smart pointers, instead of raw pointers.
Two side notes:
The const in a parameter passed by value (const size_t index) is useless and your compiler will ignore it. You can try declaring it with const and removing the const in the implementation: the compiler will correctly consider that your implementation matches the declaration.
The canonical way to implement the non-const version of operator[] is as follows:
As follows
Bird &operator[](size_t index) {
return const_cast<Bird&>(const_cast<const Aviary*>(this)->operator[](index));
}
I know all those const_cast look ugly, but they are both safe and this is the right way to ensure that both versions of operator[] do the same (you just need to maintain the const version from now on), while also making sure that your are not doing any non-const operation in the const version.
Apart from that, the problem with your code is that you are returning pointers, not (references to) the values pointed by them, as Luchian and ForEveR have already pointed out.
You need to dereference:
return *(birds[index]);
birds[index] is a Bird*, so you can't directly return it as a Bird&.

Qt - QList const correctness

A QList<T *> can't easily be const-correct. Consider the function
void f(QList<T *> list)
{
list[0]->constFunction();
}
I can change f to
void f(QList<const T *> list)
but then I can't do
f(QList<T *>()); //Compile error
anymore, since the compiler can't implicitely cast QList<T *> to QList<const T *>. However, I can explicitely reinterpret-cast the QList as follows:
template <typename T> inline QList<const T *> &constList(const QList<T *> &list)
{
return (QList<const T *> &)list;
}
This enables me to use the constList template function to cast any QList<T *> into a QList<const T *>, as in
f(constList(QList<T *>()));
and it seems to work fine, but is it actually safe to do this?
The casting function you're considering, …
template< class T >
inline QList<T const*>& constList( QList<T*> const& list )
{
return reinterpret_cast< QList<T const*>& >(
const_cast< QList<T*>& >( list )
);
}
… may be practical (probably QList does not change its object representation depending on the const-ness of the element type), but it can break const correctness.
First, because casting away the const-ness of the list itself is not const correct: it allows you to change an originally const list.
But even if that formal argument const is removed, like …
template< class T >
inline QList<T const*>& constList( QList<T*>& list )
{
return reinterpret_cast< QList<T const*>& >(
list
);
}
… there is still a const correctness problem.
The reason is that the list constitutes an additional level of indirection, and with your function is not itself const. Thus, after using your function to get a reference to the list with alleged pointer-to-const elements, you can store in that list a pointer to something that is really const. And then you can use the original list to modify that really const item, bang.
It's the same reason that there is no implicit conversion from T** to T const**.
What you can do without such problems is, with an already const list of pointers to objects, make those pointed to objects const:
template< class T >
inline QList<T const*> const& constList( QList<T*> const& list )
{
return reinterpret_cast< QList<T const*> const& >(
list
);
}
Formally there's still the reinterpret_cast as a potential problem, but anyone specializating the representation of QList on constness of elements would presumably deserve whatever they got. :-)
Cheers & hth.,
Const correctness idea is weak and what you found is one of the many reasons. Constness concept only captures a single bit of semantic (change/don't change) and does so badly and at a quite high syntax cost that sometimes even requires code duplication.
One problem of this concept is that it doesn't scale well by composition: for example I could be interested to pass a function a const vector of non-const objects, or a non-const vector of const objects, or a const vector of const objects and getting the syntax right is expensive... just consider how standard c++ was forced to introduce const_iterator because that is of course different from a const iterator.
Over the years I moved from the zealot position of using const correctness in every place I could to the opposite of using it only where I'm forced to. Experience taught me that code that is not obsessed with const correctness becomes cleaner and that const correctness machinery never really catches (at least for me) any logical error but only errors about the const correctness machinery itself. Unfortunately const correctness is one of the things in C++ that you are forced to use because C++ rules say so and there is no way to just avoid using it.
I know I'm going to be downvoted for this post but my suggestion is to keep a critical eye on whatever you read about C++ on this subject; keep the brain on and judge objectively. Just because would be nice for something being true (e.g. that const correctness helps the programmer) unfortunately it doesn't mean it's really true.
No matter how big is the name that signed the book.
Also remember that if a position requires all the rest of the world to be wrong then it's probably a good idea to be at least a little skeptic: most languages, even those born after C++, don't implement this concept.