In various situations I have a collection (e.g. vector) of objects that needs to be processed by a number of functions. Some of the functions need to modify the objects while others don't. The objects' classes may inherit from an abstract base class. Hence, I have something like this:
class A
{
public:
virtual void foo() const = 0;
virtual void bar() = 0;
/* ... */
};
void process_1(std::vector<std::reference_wrapper<A>> const &vec);
void process_2(std::vector<std::reference_wrapper<A const>> const &vec);
Obviously (?) I can't pass the same vector of std::reference_wrapper<A>s to both process_1 and process_2. Solutions I've considered so far include:
Using a C-style cast or reinterpret_cast on a reference to vec
Writing my own reference wrapper that has T& get() and T const & get() const instead of T& get() const
Refactoring with e.g. methods that take a wrapper instead of the vector
Having copies of the vector with and without const
Not using const in reference_wrapper's argument
None of these seems very elegant. Is there something else I could do?
Range adapters.
A range adapter takes a range as input (a container is a range, as it has begin and end returning iterators), and returns a range with different properties.
You'd cast your reference wrappers to the const variant when you dereference the iterator.
boost has iterators that will do this for you (transform iterators), and tools to help write conforming iterators, but it can be done from scratch with some work.
A bit of extra work could even keep the typenames sane.
Even lacking elegance, I would make a reference wrapper:
#include <functional>
template <typename T>
class ReferenceWrapper
{
public:
ReferenceWrapper(T& ref)
: m_ref(ref)
{}
ReferenceWrapper(const std::reference_wrapper<T>& ref)
: m_ref(ref)
{}
const T& get() const noexcept { return m_ref.get(); }
T& get() noexcept { return m_ref.get(); }
operator const T& () const noexcept { return m_ref.get(); }
operator T& () noexcept { return m_ref.get(); }
private:
std::reference_wrapper<T> m_ref;
};
It is a tiny class modeling the original requirements.
Related
If I have the following:
class Animal {};
class Penguin : public Animal {};
class Snake : public Animal {};
class Zoo
{
std::vector<std::shared_ptr<Animal>> animals;
public:
const std::vector<std::shared_ptr<Animal>>& GetAnimals() { return animals; }
std::shared_ptr<Penguin> AddPenguin()
{
auto result = std::make_shared<Penguin>();
animals.push_back(result);
return result;
}
std::shared_ptr<Snake> AddSnake()
{
auto result = std::make_shared<Snake>();
animals.push_back(result);
return result;
}
};
I'd like to keep const correctness, and be able to add the following method:
const std::vector<std::shared_ptr<const Animal>>& GetAnimals() const
{
return animals;
}
However, that doesn't compile because the return type doesn't match animals. As the const is embedded deep in the type, const_cast isn't able to convert.
However, this compiles and appears to behave:
const std::vector<std::shared_ptr<const Animal>>& GetAnimals() const
{
return reinterpret_cast<const std::vector<std::shared_ptr<const Animal>>&>(animals);
}
I realize reinterpret_casts can be dangerous, but are there any dangers to use it in this scenario? Do the types being cast between have the same memory layout? Is the only effect of this to prevent the caller from then calling any non-const methods of Animal?
Update
I've realized this isn't entirely const correct. The caller could call .reset() on one of the elements of the vector, which would still modify the zoo. Even so, I'm still intrigued what the answer is.
Update on the update
I got that wrong, the code I was trying accidentally copied the shared_ptr and so the shared_ptr in the vector can't be reset when the vector is const.
std::shared_ptr<Animal> and std::shared_ptr<const Animal> are fundamentally different types. Messing with reinterpret_cast can lead to very strange bugs down the road (mostly due to optimizations, I would imagine). You have two options: create a new std::shared_ptr<const Animal> for each std::shared_ptr<Animal>, or return a complex proxy type (something like a view of the vector).
That said, I question the need for GetAnimals. If Zoo is meant to be a collection of pointers to animals, can't you provide access functions like size, operator[], and perhaps iterators? This does involve more effort, but if all you want is a function that returns the whole vector, why have a Zoo class in the first place? If Zoo contains other data and manages more than just a vector of animals, then I would make a separate class to take care of that part, AnimalList or something. That class can then provide appropriate access functions.
Something else you might try is to keep a std::shared_ptr<std::vector<Animal>> instead that you can easily convert into a std::shared_ptr<const std::vector<Animal>>. That may or may not be relevant depending on the reason you need shared pointers.
You can probably solve your problem with std::experimental::propagate_const. It is a wrapper for pointer-like types that properly propagates const-correctness.
A const std::shared_ptr<Animal> holds a mutable Animal. Retrieving a mutable reference to the mutable animal is legal, because the pointer itself is not changed. Vice versa, a std::shared_ptr<Animal const> will always hold a const Animal. You would have to explicitly cast away constness to mutate the held element which is ugly to say the least. Dereferencing a std::experimental::propagate_const<std::shared_ptr<Animal>> on the other hand returns a Animal const& if it is const, and a Animal& if it is not const.
If you wrap your shared pointers in std::experimental::propagate_const you can equip Zoo with a const and a non-const getter for your animals vector and have const-correctness (or you could make animals a public data member, since the getters don't do anything special. This would make your API more transparent):
#include <vector>
#include <memory>
#include <experimental/propagate_const>
#include <type_traits>
class Animal {};
class Penguin : public Animal {};
class Snake : public Animal {};
class Zoo
{
template <typename T>
using pointer_t = std::experimental::propagate_const<std::shared_ptr<T>>;
std::vector<pointer_t<Animal>> animals;
public:
// const-getter
auto const& GetAnimals() const
{
return animals;
}
// non-const getter
auto& GetAnimals()
{
return animals;
}
std::shared_ptr<Penguin> AddPenguin()
{
auto result = std::make_shared<Penguin>();
animals.push_back(result);
return result;
}
std::shared_ptr<Snake> AddSnake()
{
auto result = std::make_shared<Snake>();
animals.push_back(result);
return result;
}
};
int main() {
Zoo zoo;
zoo.AddSnake();
// non-const getter will propagate mutability through the pointer
{
auto& test = zoo.GetAnimals()[0];
static_assert(std::is_same<Animal&, decltype(*test)>::value);
}
// const-getter will propagate const through the pointer
{
Zoo const& zc = zoo;
auto& test = zc.GetAnimals()[0];
static_assert(std::is_same<Animal const&, decltype(*test)>::value);
}
return 0;
}
https://godbolt.org/z/1rd8YraMc
The only downsides I can think of are the discouraging "experimental" namespace and the fact that afaik MSVC hasn't implemented it yet, so it is not as portable as it could be....
If that bothers you, you can write your own propagate_const wrapper type, as #Useless suggested:
template <typename Ptr>
class propagate_const
{
public:
using value_type = typename std::remove_reference<decltype(*Ptr{})>::type;
template <
typename T,
typename = std::enable_if_t<std::is_convertible<T, Ptr>::value>
>
constexpr propagate_const(T&& p) : ptr{std::forward<T>(p)} {}
constexpr value_type& operator*() { return *ptr; }
constexpr value_type const& operator*() const { return *ptr; }
constexpr value_type& operator->() { return *ptr; }
constexpr value_type const& operator->() const { return *ptr; }
private:
Ptr ptr;
};
https://godbolt.org/z/eGPPPxef4
Let a polymorphic Base class have a pure virtual method insert on a stl container member (vector in this case). The function should be able to take iterator of containers like set, vector, list etc, but also take into account the type of reference (move semantics)
The pure virtual nature of the function make using template functions impossible. Afaik iterators of stl containers are separate type, thats why templates are useful. However the polymorphism is necessary. Also I noticed that there is std::move_iterator which is able to encapsulate all types of iterators.
Are there other "iterator wrappers" which I can use to define a pure virtual method in Base which takes all sorts of iterators and also acts like perfectly forwarding function template such that clients can pass iterators and move iterators?
Before introducing polymorphism the function was like this:
vector<Class> v;
template<typename Iter>
void insert(Iter begin, Iter end) {
v1.insert(begin, end, std::end(v));
}
but now there derived classes which behave slightly different on insert (mutexes, notify observers etc). It would be nice to have something like the following:
vector<Class> v;
virtual void Base::insert(GenericIter begin, GenericIter end) = 0;
[…]
void DerivedMT::insert(GenericIter begin, GenericIter end) override
{
mutex.lock();
v1.insert(begin, end, std::end(v));
mutex.unlock();
}
[…]
void DerivedObserved::insert(GenericIter begin, GenericIter end) override
{
v1.insert(begin, end, std::end(v));
notifyObservers();
}
You can't accept all the various iterators and maintain runtime polymorphism because you would then violate Liskov Substitution Principle. That is, a polymorphic bidirectional iterator will not work with wrapped forward iterator, since the latter can only be incremented. Also there are sorted associative containers, whose iterators you can not use for sorting, etc:
in case an implementor would want not to skip, but to sort the elements
in case an implementor would want to do a particular kind of search
So, the intent of a template iterator for a function is to provide a freedom for an interface implementor to do whatever he desires given he has two iterators. But with runtime polymorphic iterators you are limiting the implementor (you kind of should).
So there are two ways:
Naive. Just declare your interface with insert(std::vector<YourType>). This will handle for your all the generic iterators you want, and an implementor is free to do whatever he desires with the range.
Implement const PolymorphicForwardIterator using traits for a Forward Iterator and type erasure.
Here is an example of how you can erase a type without heap allocations:
class PolymorphicReference final
{
public:
template <typename RefT>
explicit PolymorphicReference(RefT &ref)
: pVTable_(std::addressof(GetVTable(ref))),
ref_(std::addressof(ref))
{}
void Say(const std::string& msg)
{
pVTable_->pSay(ref_, msg);
}
int Number() const
{
return pVTable_->pNumber(ref_);
}
private:
struct VTable
{
virtual void pSay(void *pRef, const std::string& msg) = 0;
virtual int pNumber(const void *pRef) = 0;
protected:
~VTable() = default;
};
template <typename RefT>
static VTable &GetVTable(const RefT&)
{
struct : VTable
{
void pSay(void *pRef, const std::string& msg) override
{
static_cast<RefT*>(pRef)->Say(msg);
}
int pNumber(const void *pRef) override
{
return static_cast<const RefT*>(pRef)->Number();
}
} static vTable;
return vTable;
}
private:
VTable *pVTable_;
void *ref_;
};
Are there other "iterator wrappers" which I can use to define a pure virtual method in Base which takes all sorts of iterators and also acts like perfectly forwarding function template such that clients can pass iterators and move iterators?
No. Either you can have a virtual function, or you can have perfect forwarding, you can't have both.
What you can have is a type-erasing range, such as boost::any_range.
class Base {
public:
virtual void insert(boost::any_range<Class, std::input_iterator_tag> range) = 0;
};
To complement the other answer, here's something to get you up and running on implementing a polymorphic iterator if that's the desired solution. Rather than a forward iterator, I modelled an input iterator since that's all you need when taking a pair as a range to insert. The full sample can be found here.
Do note that this type fully models std::input_iterator, which means that it can be used anywhere any other input iterator can be used.
template<typename T>
class any_const_input_iterator_of {
// Store the actual iterator without its type.
std::any _erased;
// Store each operation we need from the actual iterator.
// Not ideal for space, but works as a starter example.
void(*_increment)(std::any& erased);
auto(*_deref)(const std::any& erased) -> const T&;
auto(*_equals)(const std::any& erased, const std::any& erased_other) -> bool;
public:
// Some required types to satisfy the iterator requirements.
using iterator_category = std::input_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = const T;
// The constructor takes the real iterator.
// Since it knows the type, it can use the type in lambdas to fill in the operations.
// Normally, you wouldn't squish the important parts here.
template<std::input_iterator Iter>
requires std::equality_comparable<Iter> and
std::same_as<T, std::iter_value_t<Iter>> // We don't want a const T& return to be a temporary
any_const_input_iterator_of(Iter iter) :
_erased(iter),
_increment([](std::any& erased) { ++std::any_cast<Iter&>(erased); }),
_deref([](const std::any& erased) -> const T& { return *std::any_cast<Iter>(erased); }),
_equals([](const std::any& erased, const std::any& erased_other) {
assert(erased.type() == erased_other.type() and "Erased iterator types differ. This is probably a bug.");
return std::any_cast<Iter>(erased) == std::any_cast<Iter>(erased_other);
}) {}
// Now that we have operations, we can use them to implement the iterator requirements.
auto operator++() -> any_const_input_iterator_of& {
_increment(_erased);
return *this;
}
auto operator++(int) -> any_const_input_iterator_of {
auto copy = *this;
++*this;
return copy;
}
auto operator*() const -> const T& {
return _deref(_erased);
}
auto operator->() const -> const T* {
return &**this;
}
friend auto operator==(const any_const_input_iterator_of& lhs, const any_const_input_iterator_of& rhs) -> bool {
return lhs._equals(lhs._erased, rhs._erased);
}
};
static_assert(std::input_iterator<any_const_input_iterator_of<int>>);
There are two interesting things you might be wondering about. First, what about comparing with a sentinel? Well, I'm not sure this is even possible. The type of the sentinel, which needs to be available inside the lambda when calling operator==, is known only inside this class's operator==. There's no way to have both the iterator type and the sentinel type both known in the same place. If you limit sentinels to a finite list of types (as I did by requiring it to be the same type as the iterator), then your options open up a bit more.
Second, what about iterators whose value type is convertible to this one instead of an exact match? What if I want to pass set<double>::iterators as any_const_input_iterator_of<int>? Well, the issue here is lifetime. If dereferencing produces a double& and _deref returns const int&, then you're creating a temporary int that goes out of scope when _deref is done. Of course you can choose to return by value here and make copies. The problem really comes when the types do match. In this case, references are fine, but returning by value denies that. This is one of those things you have to live with when deciding to erase type information.
I'm having a custom structure called SortedArrayList<T> which sorts its elements according to a comparator, and I would like to prevent assigning using operator[].
Example:
ArrayList.h
template <typename T> class ArrayList : public List<T> {
virtual T& operator[](const int& index) override; //override List<T>
virtual const T operator[](const int& index) const override; //override List<T>
}
SortedLinkedList.h with following operators
template <typename T> class SortedArrayList : public ArrayList<T> {
public:
SortedArrayList<T>(const std::function<bool(const T&, const T&)>& comparator);
T& operator[](const int& index) override; //get reference (LHS)
const T operator[](const int& index) const override; //get copy (RHS)
}
Test.h
ArrayList<int>* regular = new ArrayList<int>();
ArrayList<int>* sorted = new SortedArrayList<int>(cmpfn);
(*regular)[0] == 5; //allow
(*regular)[0] = 5; //allow
(*sorted)[0] == 7; //allow
(*sorted)[0] = 7; //except
Is this operation possible?
By prevent I mean throwing an exception or something what will warn user to not do it.
Prefer aggregation over inheritance:
template <typename T> class SortedArrayList {
ArrayList<T> m_the_list;
public:
SortedArrayList<T>(const std::function<bool(const T&, const T&)>& comparator);
const T& operator[](const int& index) const {return m_the_list[index];}; // always get const reference
// Can act as a *const* ArrayList<T>, but not as a mutable ArrayList<T>, as that would violate Liskov's substitution principle.
operator const ArrayList<T>&() const {return m_the_list;}
}
As Stephen Newell correctly points out, when you're using inheritance, you're guaranteeing your class SortedArrayList can act as an ArrayList in every possible scenario. This is clearly not the case in your example.
You can read more here about how violating Liskov's Substitution Principle is a bad idea.
You should not do this. It indicates an improper design See the C++ FAQ on Inheritance. Your subclass doesn't fulfill the "is-a" requirement for public inheritance if it can't be used in all ways as the base class (LSP).
If you want to have one type of container that allows member replacement and another that doesn't, then the define the base class that just allows const member access (no need to make it virtual). Then branch from there to MutableList and ImmutableList, and let SortedArrayList derive from Immutable list.
Seems to me like the best practice here would be to implement an at(const int& index) method instead of overloading []. That would be more clear to the user of the interface anyway.
There is a similar function in std::map and other std data structures. For example: http://www.cplusplus.com/reference/map/map/at/
Why do you pass the index as reference at all? Absolutely no need for...
I personally recommend to use unsigned integer types for array indices (what would be the meaning of a negative index anyway???).
const for a type returned by value is (nearly) meaningless - it will be copied to another variable anyway (which then will be modifiable), but you prevent move semantics...
So:
T& operator[](unsigned int index); //get reference (LHS)
T operator[](unsigned int index) const; //get copy (RHS)
(Just some improvement suggestions...)
Now to the actual question: Disallowing modification is quite easy:
//T& operator[](unsigned int index); //get reference (LHS)
T const& operator[](unsigned int index) const; //get copy (RHS)
Just one single index operator, always returning const reference... If user can live with reference, fine, otherwise he/she will copy the value anyway...
Edit in adaption to modified question:
As now inheritance is involved, the stuff gets more complicated. You cannot just get rid of some inherited function, and the inherited one will allow element modification.
In the given situation, I'd consider a redesign (if possible):
class ArrayListBase
{
public:
T const& operator[](unsigned int index) const;
// either copy or const reference, whichever appears more appropriate to you...
};
class ArrayList : public ArrayListBase
{
public:
using ArrayListBase::operator[];
T& operator[](unsigned int index);
}
class SortedArrayList : public ArrayListBase
{
public:
// well, simply does not add an overload...
}
The insertion function(s) might be pure virtual in the base class (where a a common interface appears suitable) or only available in the derived classes. Decide you...
I wrote this C++17 code and expected it to work out of the box.
class putc_iterator : public boost::iterator_facade<
putc_iterator,
void,
std::output_iterator_tag
>
{
friend class boost::iterator_core_access;
struct proxy {
void operator= (char ch) { putc(ch, stdout); }
};
auto dereference() const { return proxy{}; }
void increment() {}
bool equal(const putc_iterator&) const { return false; }
};
I'm trying to match the behavior of all the standard OutputIterators by setting my iterator's member typedefs value_type and reference to void (since those types are meaningless for an iterator whose operator* doesn't return a reference).
However, Boost complains:
In file included from prog.cc:2:
/opt/wandbox/boost-1.63.0/clang-head/include/boost/iterator/iterator_facade.hpp:333:50: error: cannot form a reference to 'void'
static result_type apply(Reference const & x)
^
It looks like Boost is trying to hard-code the generated operator*'s signature as reference operator*() const. That is, boost::iterator_facade could deduce the proper return type of operator*() by simply passing along whatever was returned by dereference(); but for some reason it's just not playing along.
What's the solution? I can't pass proxy as a template parameter of the base class since proxy hasn't been defined yet. I could pull proxy out into a detail namespace:
namespace detail {
struct proxy {
void operator= (char ch) { putc(ch, stdout); }
};
}
class putc_iterator : public boost::iterator_facade<
putc_iterator,
void,
std::output_iterator_tag,
detail::proxy
>
{
friend class boost::iterator_core_access;
auto dereference() const { return detail::proxy{}; }
void increment() {}
bool equal(const putc_iterator&) const { return false; }
};
but that seems awkward and is definitely something that "shouldn't be necessary."
Is this a bug in iterator_facade? Is it a feature-not-a-bug? If the latter, then how am I supposed to use it to create OutputIterators?
Also, a minor nitpick: even my workaround with the detail namespace is "wrong" in the sense that it makes std::is_same_v<putc_iterator::reference, detail::proxy> when what I want (for parity with the standard iterators) is std::is_same_v<putc_iterator::reference, void>.
Boost Iterator Facade was good at the time, but now it is outdated as it is not very flexible (it doesn't play well with auto and with r-value references that in principle can be creating by dereferencing a r-value iterator). I am not againts the facade concept, but it could be upgraded to C++11.
In addition now with C++11 is easier to write iterator from scratch.
Anyway, if you need to define a reference just to comply with the arguments to be passed, (and if you promise not use it) you can use void* instead of void. (Or perhaps for consistency use proxy& and define it outside the class).
class putc_iterator : public boost::iterator_facade<
putc_iterator,
void*,
std::output_iterator_tag
>
{
friend class boost::iterator_core_access;
struct proxy {
void operator= (char ch) { putc(ch, stdout); }
};
auto dereference() const { return proxy{}; }
void increment() {}
bool equal(const putc_iterator&) const { return false; }
};
So basically what I want to do is to have a pure virtual method returning an iterator to an arbitrary collection of a concrete type, e.g in pseudo code:
virtual Iterator<T> getIterator() const = 0;
The user of this class actually don't care what implementation the child class uses. It could be a set, vector, list, array etc.
I'm aware of the std::iterator class but I cant find a way to specify it correctly in order to work with a simple vector.
virtual std::iterator<std::random_access_iterator_tag,T> getIterator() const = 0;
myVector.begin() // compilation error in implementation
defining std::iterator with const T as type parameter hasn't worked too. I also tried leaving T and instead defining the pointer and reference types as const T* and const T&.
By taking a look at the std::vector implementation, I found out that std::vector::const_iterator actually derives from _Iterator012 deriving from _Iterator_base.
It really bugs me that there isn't any way to work with arbitrary collections in std.
Implementing my classes as templates like in <algorithm> is not an option for me due two reasons:
No control over the actual value type
I simply don't want to make my classes templates complicating my design a lot and making things less flexible.
The used type parameter T was just for demonstration, actually this is a concrete type.
Here's a basic and very rudimentary skeleton approach using type erasure. You'll have to fill in a lot of missing details, though!
#include <memory>
template <typename T>
class TEIterator
{
struct TEImplBase
{
virtual ~TEImplBase() { }
virtual std::unique_ptr<TEImplBase> clone() const = 0;
virtual void increment() = 0;
virtual T & getValue() = 0;
T * getPointer() { return std::addressof(getValue()); }
};
template <typename Iter>
struct TEImpl
{
Iter iter;
TEImpl(Iter i) : iter(i) { }
virtual T & getValue()
{ return *iter; }
virtual std::unique_ptr<TEImplBase> clone() const
{ return std::unique_ptr<TEImplBase>(new TEImpl<Iter>(*this)); }
virtual void increment()
{ ++iter; }
};
std::unique_ptr<TEImplBase> impl;
public:
template <typename T>
TEClass(T && x)
: impl(new TEImpl<typename std::decay<T>::type>(std::forward<T>(x)))
{
}
TEClass(TEClass && rhs) = default;
TEClass(TEClass const & rhs) : impl(rhs.impl.clone()) { }
TEIterator & operator++()
{
impl->increment();
return *this;
}
T & operator*() { return impl->getValue(); }
T * operator->() { return impl->getPointer(); }
};
Usage:
std::vector<int> v;
std::deque<int> dq;
TEIterator<int> a = v.begin(), b = dq.end();
If you want to use a virtual method, you cannot use an arbitrary return value. What you can do, is define a base class, which is a wrapper around iterators, and subclass from that wrapper class.
But even then, you must restrict yourself to the smallest common denominator, since there are several iterator classes in the C++ standard library.
So, AFAICS, such a method with arbitrary iterators isn't really feasible without using templates.