ARTICLE AD BOX
You can't sensibly return pointers from begin and end, because you can't provide an overload of == for two pointer types, nor can you get an int from the dereference of such a pointer that for is defined to use.
If you have subclasses B and C with different containers, you could have virtual boost::any_range<int> getTestRangeInitializer() = 0 in A. However it could well be quicker to copy the values into a std::vector<int>, and return that.
class A { public: virtual std::vector<int> getTestRangeInitializer() = 0; }; class B : public A { std::list<int> data; public: std::vector<int> getTestRangeInitializer() override { return { std::from_range, data }; } }; class C : public A{ std::set<int> data; public: std::vector<int> getTestRangeInitializer() override { return { std::from_range, data }; }; };66.6k2 gold badges54 silver badges103 bronze badges
2 Comments
Range-based for doesn’t work with TestRangeInitializer*. It expects a range object with begin()/end() returning the same iterator type by value. Your design returns pointers and mismatched types (TestRange* vs int), so it cannot compile. Either return a proper range (by value/reference) or wrap your polymorphic iterator in a value-type iterator.
1221 silver badge9 bronze badges
2 Comments
C++17 allows different begin/end types but they must be comparable TestRange* and int aren’t. For polymorphism keep the pointer inside a value-type iterator wrapper: class Iterator { std::unique_ptr<TestRange> impl; public: Iterator(std::unique_ptr<TestRange> p) : impl(std::move(p)) {} int operator*() const { return impl->deref(); } Iterator& operator++() { impl->inc(); return *this; } bool operator!=(const Iterator& other) const { return !impl->equals(*other.impl); } }; This keeps polymorphism internally, makes the iterator a proper val
2026-03-30T12:51:58.663Z+00:00
As others have pointed out, the int end() { return -1; } can be tricky as there is no native comparison between pointers and integers.
Also compilers which don't support C++17 treat different return types on begin() and end() as error.
The probably easiest solution would be a TestRange* end() { return nullptr; }.
One big problem of your shown code is that it would produce memory leaks during every iteration.
You should use smart pointers or return raw pointers or references to instances, that are already stored and kept alive somewhere else, e.g. in a container on the current instance.
Besides that I see no problems with your approach except that it is a bit unusual.
Bonus hint:
With the raw pointers you could even use a covariant signature on your subtypes. I won't be surprised if this feature is unknown as there are only very rare situations where this can be used.
In short: If you return a raw pointer or reference, then even the function signature on the subtypes is allowed to return a narrower type instead of the type defined on the derived signature (TestRangeB* instead of TestRange* and TestRangeInitializerB* instead of TestRangeInitializer*).
Note that this works only with raw pointers and references, but not with any templates like smart pointers. This is the reason why it can be used only in rare situations.
Instead of
class B : public A { class TestRangeB : public TestRange; class TestRangeInitializerB : public TestRangeInitializer { TestRange* begin() override { return new TestRangeB(); } }; TestRangeInitializer* getTestRangeInitializer() { return new TestRangeInitializerB(); }; };you can declare it as
class B : public A { class TestRangeB : public TestRange; class TestRangeInitializerB : public TestRangeInitializer { TestRangeB* begin() override { return new TestRangeB(); } }; TestRangeInitializerB* getTestRangeInitializer() { return new TestRangeInitializerB(); }; };Thus anybody who is aware that the TestRangeInitializer and iterator were generated from a B can see and access B-specific details on the returned instances.
7721 silver badge13 bronze badges
Explore related questions
See similar questions with these tags.

