Cast Vector<T> to Vector<Const T>

Cast vectorT to vectorconst T

If you have a const vector<int> you cannot modify the container, nor can you modify any of the elements in the container. You don't need a const vector<const int> to achieve those semantics.

Casting vectorint to const vectorconst int

You cannot cast a std::vector<int> to const std::vector<const int>.

Besides, it does not make sense to use a std::vector<const int> at all. It doesn't give you any more safety than a const std::vector<int>.

Not only that, C++ does not allow construction of std::vector<const T>. See Does C++11 allow vector<const T>? for more info.

Is there a way to convert std::vectorconst T* to std::vectorT* without extra allocations?

The short answer is: no. std::vector<Object*> and std::vector<const Object*> are two different, independent classes. They are as different from each other as class A is from class B. It is often thought that just because both of them start with std::vector, that they are somehow related to each other. This is not true, and for that reason there is no way to convert one to the other, "in place". Each one of these vector classes own their corresponding internal data(), and will not willingly give it up to some other, strange class.

The long answer is still no, but in many cases it's possible to work around this in order to avoid manual code duplication. The truth of it is that code duplication is inevitable in most of these kinds of situations, and the best that can be done is to avoid manual code duplication.

One common approach is have both the constant and the mutable class method be facades for a single, shared, private template:

// Header file:

class Storage {

public:

std::vector<const Object*> aggregate_objects() const;

std::vector<Object*> aggregate_objects();

private:

template<typename v_type> void make_aggregate_objects(v_type &v) const;
};

// In the translation unit:

template<typename v_type> void Storage::make_aggregate_objects(v_type &v) const
{
// Now, create 'v' here... v.reserve(), v.push_back(), etc...
}

std::vector<const Object*> Storage::aggregate_objects() const
{
std::vector<const Object *> v;

make_aggregate_objects(v);

return v;
}

std::vector<Object*> Storage::aggregate_objects()
{
std::vector<const Object *> v;

make_aggregate_objects(v);

return v;
}

The compiler will still generate two nearly identical chunks of code, but at least it's not you doing all the typing.

Another, similar approach, is to pass a lambda to the template function instead of passing a vector object, with the private template function using the lambda function as a callback, to construct the returned vector. With a bit of type erasure, and some help from std::function, the private class method can be turned into an ordinary method, instead of a template method.

Move a vectorT* to vectorconst T*

I'm going to attack this from another angle. And address a possible design issue. You didn't specify what comes in the ..., but assuming get populates a vector and then returns it, the solution in my view is to lift the code that does the populating outside of both functions.

template<typename Int>
void do_get(std::vector<Int*>& v) {
// Populate v
}

auto get() {
std::vector<int*> ret;
do_get(ret);
return ret;
}

auto getConst() {
std::vector<const int*> ret;
do_get(ret);
return ret;
}

One source of truth for the populating logic. And while the two original functions are identical, it's negligible. Furthermore on a sane implementation it won't do any superfluous copies, because RVO is amazing.

Cannot cast from vectorT to T

This is because v is not a vector, it is a pointer to vector. Therefore, you need a dereference operator:

if (isReflex((*v)[i-2], (*v)[i-1], (*v)[i], (*v)[i+1], (*v)[i+2], (*v)[i+3]))

The reason the error message may not look entirely clear is that [] operator applies to pointers as well, and behaves like a dereference operator with an offset. In other words, C++ compiler treats variable v as a built-in array of vectors, applies index [i-2] to that array, and reports an error, because the type of v[i-2] expression is a vector.

The real vector is passed as const vector<T>* to a function

You can make a reference variable to keep the old syntax:

const vector<T> *pv // function parameter
const vector<T>& v = *pv;
// This will work now
if (isReflex(v[i-2], v[i-1], v[i], v[i+1], v[i+2], v[i+3])) {
...
}

How can I propagate const when returning a std::vectorint* from a const method?

You're asking for std::experimental::propagate_const. But since it is an experimental feature, there is no guarantee that any specific toolchain is shipped with an implementation. You may consider implementing your own. There is an MIT licensed implementation, however. After including the header:

using namespace xpr=std::experimental;
///...
std::vector<xpr::propagate_const<int*>> my_ptr_vec;

Note however that raw pointer is considered evil so you may need to use std::unique_ptr or std::shared_ptr. propagate_const is supposed to accept smart pointers as well as raw pointer types.



Related Topics



Leave a reply



Submit