Can/Should i inherit from STL iterator to implement my own iterator class? If no, why not?
Short answer
Many consider that the class std::iterator does not offer much compared to regular type aliases, and even obfuscates them a bit by not explicitly providing the names and relying on the order of the template parameters instead. It is deprecated in C++17 and is likely to be gone in a few years.
This means that you shouldn't use std::iterator anymore. You can read the whole post below if you're interested in the full story (there's a bit of redundancy since it has been started before the deprecation proposal).
Legacy answer
You can ignore everything below if you're not interested in history. The following fragments even contradict themselves several times.
As of today (C++11/C++14), the standard seems to imply that it isn't a good idea anymore to inherit from std::iterator to implement custom iterators. Here is a brief explanation, from N3931:
Although the Standard has made this mistake almost a dozen times, I recommend not depicting directory_iterator and recursive_directory_iterator as deriving from std::iterator, since that's a binding requirement on implementations. Instead they should be depicted as having the appropriate typedefs, and leave it up to implementers to decide how to provide them. (The difference is observable to users with is_base_of, not that they should be asking that question.)
[2014-02-08 Daniel comments and provides wording]
This issue is basically similar to the kind of solution that had been used to remove the requirement to derive from unary_function and friends as described by N3198 and I'm strongly in favour to follow that spirit here as well. I'd like to add that basically all "newer" iterator types (such as the regex related iterator) don't derive from std::iterator either.
The paper cites N3198 which itself states that it follows the deprecation discussed in N3145. The reasons for deprecating the classes that only exist to provide typedefs are given as such:
Our experience with concepts gives us confidence that it is rarely necessary to depend on specific base class-derived class relations, if availability of types and functions is sufficient. The new language tools allow us even in the absence of language-supported concepts to deduce the existence of typenames in class types, which would introduce a much weaker coupling among them. Another advantage of replacing inheritance by associated types is the fact, that this will reduce the number of cases, where ambiguities arise: This can easily happen, if a type would inherit both from unary_function and binary_function (This makes sense, if a functor is both an unary and a binary function object).
tl;dr: classes which only provide typedefs are now deemed useless. Moreover, they increase coupling when it is not needed, are more verbose, and can have unwanted side effects in some corner cases (see the previous quotation).
Update: issue 2438 from N4245 seems to actually contradict what I asserted earlier:
For LWG convenience, nine STL iterators are depicted as deriving from std::iterator to get their iterator_category/etc. typedefs. Unfortunately (and unintentionally), this also mandates the inheritance, which is observable (not just through is_base_of, but also overload resolution). This is unfortunate because it confuses users, who can be misled into thinking that their own iterators must derive from std::iterator, or that overloading functions to take std::iterator is somehow meaningful. This is also unintentional because the STL's most important iterators, the container iterators, aren't required to derive from std::iterator. (Some are even allowed to be raw pointers.) Finally, this unnecessarily constrains implementers, who may not want to derive from std::iterator. (For example, to simplify debugger views.)
To sum up, I was wrong, #aschepler was right: it can be used, but it is certainely not required - it isn't discouraged either. The whole "let's remove std::iterator" thing exists for the standard not to constrain the standard library implementers.
Round 3: P0174R0 proposes to deprecate std::iterator for a possible removal in the future. The proposal is already pretty good at explaining why it should be deprecated, so here we go:
The long sequence of void arguments is much less clear to the reader than simply providing the expected typedefs in the class definition itself, which is the approach taken by the current working draft, following the pattern set in C++14 where we deprecated the derivation throughout the library of functors from unary_function and binary_function.
In addition to the reduced clarity, the iterator template also lays a trap for the unwary, as in typical usage it will be a dependent base class, which means it will not be looking into during name lookup from within the class or its member functions. This leads to surprised users trying to understand why the following simple usage does not work:
#include <iterator>
template <typename T>
struct MyIterator : std::iterator<std::random_access_iterator_tag, T> {
value_type data; // Error: value_type is not found by name lookup
// ... implementations details elided ...
};
The reason of clarity alone was sufficient to persuade the LWG to update the standard library specification to no longer mandate the standard iterator adapators as deriving from std::iterator, so there is no further use of this template within the standard itself. Therefore, it looks like a strong candidate for deprecation.
This is becoming a bit tiring and not everyone seems to agree, so I will let you draw your own conclusions. If the committee eventually decides that std::iterator should be deprecated, then it will make it pretty clear that you shouldn't use it anymore. Note that the follow-up paper highlights a great support for the removal of std::iterator:
Update from Jacksonville, 2016:
Poll: Deprecate iterator for C++17??
SF F N A SA
6 10 1 0 0
In the above poll results, SF, F, N, A and SA stand for Strongly For, For, Neutral, Against and Strongly Against.
Update from Oulu, 2016:
Poll: Still want to deprecate std::iterator?
SF F N A SA
3 6 3 2 0
P0619R1 proposes to remove std::iterator, possibly as soon as C++20, and also proposes to enhance std::iterator_traits so that it can automatically deduce the types difference_type, pointer and reference the way std::iterator does when they're not explicitly provided.
If you mean std::iterator: yes, that's what it's for.
If you mean anything else: no, because none of the STL iterators have virtual destructors. They're not meant for inheritance and a class inheriting from them might not clean up properly.
No one should not because of the potential problems that might be encountered. Probably you are better off using Composition rather than Inheritance with STL Iterators.
Undefined Behavior due to absence of virtual destructors:
STL containers & iterators are not meant to act as base classes as they do not have virtual destructors.
For classes with no virtual destructors being used as Base class, the problem arises when deallocating through a pointer to the base class (delete, delete[] etc). Since the classes don't have virtual destructors, they cannot be cleaned up properly and results in Undefined Behavior.
One might argue that there would not be a need to delete the iterator polymorphically & hence nothing wrong to go ahead with deriving from STL iterators, well there might be some other problems like:
Inheritance maynot be possible at all:
All iterator types in the standard container are Implementation defined.
For e.g: std::vector<T>::iterator might be just a T*. In this case, you simply cannot inherit from it.
The C++ standard has no provisions demanding that say std::vector<T>::iterator does not
use inheritance inhibiting techniques to prevent derivation. Thus, if you are deriving from a STL iterator you are relying on a feature of your STL that happens to allow derivation. That makes such an implementation non portable.
Buggy behaviors if not implemented properly:
Consider that you are deriving from vector iterator class like:
class yourIterator : std::vector<T>::iterator { ... };
There might be a function which operates on the vector iterators,
For ex:
void doSomething(std::vector<T>::iterator to, std::vector<T>::iterator from);
Since yourIterator is a std::vector<T>::iterator you can call doSomething() on your container class but you will be facing the ugly problem of Object Slicing. The doSomething() has to be implemented in a proper templated manner, to avoid the
problem.
Problems while using Standard Library Algorithms:
Consider you are using the derivation from vector iterator, and then you use a Standard library algorithm like std::transform()
For Ex:
yourIterator a;
yourIterator b;
...
std::transform( a++, b--, ... );
The postfix operator ++ returns a std::vector<T>::iterator and not a
yourIterator resulting in a wrong template being chosen.
Thus, Inheriting from STL Iterators is possible indeed but if you ready to dig out all such and many other potential problems and address them, Personally I won't give it the time and the effort to do so.
If you're talking about std::iterator template, then yes, you should, but I hope you do understand that it has no functionality, just a bunch of typedefs. The pro of this decision is that your iterator can be fed to iterator_traits template.
If, on the other hand, you're talking about some specific STL iterator, like vector<T>::iterator or other, then the answer is a resounding NO. Let alone everything else, you don't know for sure that it's actually a class (e.g. the same vector<T>::iterator can be just typedefed as T*)
Related
I was reading this blogpost about the trouble of customization points in C++17, so I wonder if there are any changes in C++20 regarding this.
I am only concerned about language changes allowing me to write my library nicer, I presume there were no changes to std:: due to backward compatibility reasons.
To make question self contained: here is my bad recap of problems mentioned in post:
ADL dance solution is easy to get wrong(eg. calling std::swap instead of using std::swap; swap(a,b);,
proper solution uses ugly boilerplate including priority inheritance trick template<size_t I> struct priority_tag : priority_tag<I-1> {}; template<> struct priority_tag<0> {};
Pre-C++20, "customization point" was an informal idiom based around ADL that various parts of the C++ standard library would sometimes make use of. C++20 created a more formal idiom, with a much more direct kind of implementation.
But C++20's proper customization point concept is rather incompatible with the pre-C++20 idiom. So it creates new customization points that operate under its new rules: std::ranges::begin/end, std::ranges::size, etc.
The nature of C++20 customization point is such that you could have used the idiom in pretty much any version of C++. C++20's concepts make writing the customized version easier, but you could use some from of SFINAE in most C++ versions to accomplish basically the same thing.
C++20 customization points are function objects, not regular template functions. As such, you cannot overload the function itself. You can customize a customization point either with a member function or with an ADL-accessible function, both of which must use the required name and interface. But this also means that you can't customize a non-user-defined type; the customization point type itself must provide any overloads for such functions.
The principle incompatibility between the two is in invoking the customization point, not so much in how you customize it. There's no need for the using dance.
Does C++20 offer any new solutions to the problem of public member invisibility and source code bloat/repetition with inherited class templates described in this question over 2 years ago ?
The "Problem"
The alleged "problem" is that, in a template, an unqualified name used in a way which isn't dependent on the specialization is truly independent of the specialization and refers to the entity with that name found at that point. The alleged source code "bloat" is using this-> to explicitly make the name dependent or qualifying the name. This is still the situation in C++20.
Just to be clear, the set of entities is not known at the point we refer to them. In the linked question, the base class depends on the template parameter, and we have only seen the primary base class template. The base class template may be specialized later and may have completely different member functions than the ones we've seen. So, any "solution" requires that a name without any obvious contextual dependence on the specialization find entities not yet declared which may be surprising.
Why It's Impossible
Any naive changes in this direction are either pretty big or have severe downsides, or both.
You could postpone all name lookup until instantiation time, discarding two phase lookup. That invites ODR violations which is silent UB, which is a huge downside.
You could restrict specialization so that you cannot specialize the base class later such that a different entity is found. That is difficult to diagnose, so it would likely be a new rule introducing silent UB.
You could opt in with a using declaration: using X::* as you propose or using class X as someone else suggested in a different context. This has the benefit of explicitness. It moves the problem a level up: if X is not dependent, presumably it should be found now, but if it is dependent, what happens? We can't instantiate it prior to instantiating the template we're in now. Thus, we can't interpret any names we see until instantiation. It has similar downsides to discarding two phase lookup.
Any of these changes would add complexity to an already complex area and would also pose significant backwards compatibility hurdles. None of them is a clear win.
Note: In C++20 they did make the rules more uniform by allowing ADL to find function templates with specified parameters to be found: f<int>(1).
Why It's Not a Problem
I doubt there would be consensus that this really is a problem. The linked question makes a poor argument. The derived class adds member function behavior to a certain base class, but a free function works better. These behaviors did not need member access, they aren't required by the language to be members, they can be found as non-members with ADL, and by using a free function they apply even when the static type you have is the base type. So, using inheritance for this is unnecessary coupling, and is a worse option.
Searching for 100s of places to add this-> and adding these 6 characters 100s of times strikes me as Code Bloat and Repetition when I have to templatize a base class
"Searching": The compiler will tell you when a name can't be found, which is better than silent bad behavior, such as making ODR violations easier to hit.
"templatize a base": Templatizing the base class doesn't trigger this. Templatizing the derived class and making the base dependent does. Yes, when templatizing the derived class, specifying that a bare name used in a way that is independent of the template parameter is in fact dependent may seem like boilerplate to some, but others might argue being explicit is clearer.
"100s of times": Seems hyperbolic.
These code patterns are used all the time in real world. Just look at CRTP. (comment on linked question)
Again, this only applies if the derived class is templated. I would dispute the commonality, but these idioms do exist and have a place.
Most importantly, though, is that CRTP is not a goal. CRTP is a hack. It's a C++ idiom because C++ lacks better facilities. CRTP allows a class to opt into certain behaviors that would otherwise be bothersome to write. Relevant C++ proposals do exist, but by and large, they have focused on making extension easier or removing boilerplate, and not on making CRTP, the hack, easier.
These are some that come to mind:
C++20: Comparisons
A very common use of CRTP is for things that require a lot of extra boilerplate. C++ required you to define operator== and operator!=, for instance. By opting into a CRTP base class, one could define only the primitive operation and have the other one generated.
C++20 fixed the underlying problem with comparisons. The typical member-wise comparison can be defaulted, and comparisons can be re-written so that != can invoke ==.
The problem is solved at the root, removing CRTP, not enhancing it.
C++20: Iterators to Ranges
Another common use of CRTP in the same vein as above is iterators. Writing custom iterators requires only a few fundamental operations: advance and dereference for forward iterators. But then there's a lot of extra seemingly unnecessary ceremony: pre-increment, post-increment, const iterators, typedefs, etc.
C++20 took a large step forward by introducing range concepts and the range library. The result is that it should be much less necessary to write a custom iterator. Ranges become a capable concept on their own, and there's a good suite of range combinators.
C++20: Concepts
C++ essentially has two systems for specifying an interface: virtual functions and concepts. They have trade-offs. Virtual functions are intrusive. But prior to C++20, concepts were implicit and emulated. One reason to use CRTP or inheritance generally would be to inject virtual functions. But in C++20, concepts are a language feature removing one big negative.
Future C++: Metaclasses
One value of CRTP in addition to the boilerplate reduction is satisfying an entire collection of multiple type requirements. A comparable class defines all the comparison operators. An clonable base defines a virtual destructor and clone.
This is the topic of metaclasses, which is not yet in C++.
See Also
See also the work on customization points which seems very interesting. And see the debates on unified function call syntax, which seems like we'll never get.
Summary
There's a very good question hiding in here about how C++20 makes it easier to reduce boilerplate, remove hacks like CRTP, and write better and clearer code. C++20 takes several steps in this regard, but they made the expression of intent easier, not a particular idiom.
I am writing a C++ library and have had this amazing idea of using as much C++2a/C++20 as possible. Thus, I am using the standard library concepts and creating my own. However, the idea of a function returning a std::vector<X> seemed non-C++20 enough to me, so I declared in my concept a return type matching std::ranges::view<X>. I've then implemented some classes that fulfill this concept.
However, the problem appeared when I wanted to devise a polymorphic wrapper class. So, let's say the concept is C and I have three implementing classes C1, C2 and C3 (but allow for more). Now I want to create a class C_virtual and a template C_virtual_impl<C c> deriving from it, which will allow me to refer to all classes fulfilling C polymorphically. However, for that to work I need a polymorphic std::ranges::view wrapper, similar in spirit to C_virtual.
I have not seen any such class in the headers and in C++ reference. Moreover, when I started implementing it myself, I quickly found myself unable to due to some requirements on iterators, in particular default constructibility, swappability and similar.
Is there a nonobvious solution in the standard library or an idiom? If not, how do I deal with the problem? Possibly a change of design will work. I certainly do not want to return a std::vector<X> or to return a V<X> where V would be a type parameter of C. How do I do this?
Range views, and many other template techniques, are not meant to be used with inheritance-based polymorphism. This is much like how vector<BaseClass> is not especially useful.
If you need runtime polymorphism, then the tool you want is not inheritance (directly); it's type erasure. That is, you have some view wrapper which uses type erasure to forward the various view operations to the erased type. This would also need to be paired with type-erased iterators that wrap the iterators of the given view.
Now of course, this means that the characteristics of the view have to be defined by the type erased wrapper. The wrapper could implement the input_range concept, but it could never fulfill more than input_range itself. Even if you put a contiguous_range type in the wrapper, the wrapper will limit the interface to that of an input_range.
As such, it's best to just avoid this case and rely on static polymorphism via templates whenever possible.
I came across class template std::unary_function and std::binary_function.
template <class Arg, class Result>
struct unary_function {
typedef Arg argument_type;
typedef Result result_type;
};
template <class Arg1, class Arg2, class Result>
struct binary_function {
typedef Arg1 first_argument_type;
typedef Arg2 second_argument_type;
typedef Result result_type;
};
Both these can be used as base class for specific purposes. But still there's no virtual destructor in these. One reason which I could guess is these are not meant to be treated polymorphically. i.e
std::unary_function* ptr;
//intialize it
//do something
delete ptr;
But if that is so, shouldn't destructor be there with protected access specifier so that compiler would break any attempt to do that.
In a well-balanced C++ design philosophy the idea of "preventing" something from happening is mostly applicable when there's a good chance of accidental and not-easily-detectable misuse. And even in that case the preventive measures are only applicable when they don't impose any significant penalties. The purpose of such classes as unary_function, binary_function, iterator etc. should be sufficiently clear to anyone who knows about them. It would take a completely clueless user to use them incorrectly.
In case of classes that implement the well-established idiom of "group member injection" through public inheritance, adding a virtual destructor to the would be a major design error. Turning a non-polymorphic class into a polymorphic one is a major qualitative change. Paying such price for the ability to use this idiom would be prohibitively unacceptable.
A non-virtual protected destructor is a different story... I don't know why they didn't go that way. Maybe it just looked unnecessarily excessive to add a member function to that purpose alone (since otherwise, these classes contain only typedefs).
Note that even though unary_function, binary_function are deprecated, iterator is not. The deprecation does not target the idiom itself. The idiom is widely used within other larger-scale design approaches, like C++ implementation of Mixins and such.
Because std::unary_function and std::binary_function are, by design, not supposed to be used for polymorphic deletion : they exist only to provide typedefs to the child classes, and have no other intent.
Being a base class in C++ does not mean that the class must exhibit any particular polymorphic behaviour.
i.e. you should never see code such as :
void foo(std::unary_function* f)
{
delete f; // illegal
}
Note that both classes are deprecated since C++11 (See N3145)
The basic reason the various type tags (e.g., there is also std::iterator<...>) don't play nicely with people believing everything derived from is meant to be a base class is that overall design of STL where they are used frowns upon the use of inheritance for polymorphism. That is, the people who proposed these classes wouldn't see any reason why anybody would want to treat anything dynamically polymorphic, especially not any of these empty-by-design type tags. Thus, little effort was made to prevent silly mistakes.
When these classes were accepted as part of the STL at large there was a lot more effort spent on removing the rough edges of STL and not so much on unimportant details. Also, having the type tags being empty could be useful as they wouldn't interfere with some of the constraints place upon classes using any access specifiers. Thus, the type tags were left empty.
As it is specifically not needed to use any of these type traits with C++11 (the return type can be determined upon use and the arguments can be perfectly forwarded) these types are being deprecated rather than getting "fixed" (assuming they are considered broken).
Is it possible to implement an any iterator with boost iterator facade?
I don't want to define implementation details in my baseclass
class Base
{
public:
typedef std::vector<int>::iterator iterator;//implementation detail
...
virtual iterator begin()=0;
virtual iterator end()=0;
};
or do i have to write one completely from scratch;
The code you've posted has fixed the type of iterators returned from Base and all it's implementantions to std::vector<int>::iterator which is probably not what you want. Jeremiah's suggestion is one way to go with one drawback: you loose compatibility with STL... I know of three implementations of a polymorphic iterator wrapper:
becker's any_iterator (which implements boost::iterator_facade)
the opaque_iterator library (google for it), or
Adobe's very interesting poly library which contains a hierarchy of STL conforming any_iterators.
The problem is harder than it might seem... I made an attempt myself mainly because I needed covariance in any_iterators type argument (any_iterator<Derived> should be automatically convertible to any_iterator<Base>) which is difficult to implement cleanly with STL like iterators. A C# like Enumerator<T> is easier to implement(*) (and imho generally a cleaner concept than STL-like pairs of iterators) but again, you "loose" the STL.
(*) = without 'yield' of course :-)
I think this may be what you're looking for:
any_iterator: Type Erasure for C++ Iterators
Here's a snippet from that page::
Overview
The class template any_iterator is the analog to boost::function for
iterators. It allows you to have a single variable and assign to it
iterators of different types, as long as these iterators have a
suitable commonality.