I have a C++ class Finder that stores a location in containers plus some additional data. Such containers have the type std::string but also char * or MyString. Say, the class looks like this (Iterator<TContainer>::Type is a trait / metafunction that returns the iterator type for a given container):
template <typename TContainer>
class Finder
{
public:
typedef typename Iterator<TContainer>::Type TIterator;
TIterator iterator;
// Initialization of iterator: How to do it generically?
// Finder {} // problem with pointers!
// Finder() : iterator(0) {} // problem with iterators!
};
The main problem now is how to initialize the iterator that can be a pointer or an iterator. If I only wanted to support my own containers then I could simply implement a constructor that takes nullptr_t following the nullptr idiom. However, since I want to support pointers, my own iterators and STL iterators, I'm a bit out of depth here.
The best thing that I can imagine is to write a getNil<>() function, e.g. the code below. However, now at least three questions arise:
Is this the best way to achieve my aim?
How to determine whether a type is a STL iterator? I would probably need some #ifs, and tailor code to each compiler/STL version to use.
Is it possible at all to get a nil iterator in the STL? Is the result of x-y in std::vector<int> x, y; int x = x-y; defined at all?
The code:
// Forward declaration.
template <typename T>
T getNil<T>();
template <typename TValue> TValue * getNil<TValue *>()
{ return NULL; }
template <typename TValue> TValue * const getNil<TValue * const>()
{ return NULL; }
template <> TValue * const getNil<MyIterator>()
{ return MyIterator(nullptr); } // nullptr from above idiom
template <> TStlIterator
boost::enable_if<
MagicallyDetermineIfIsStlIterator<TStlIterator>::value,
TStlIterator>
getNil<TStlIterator>()
{ return MyIterator(nullptr); } // nullptr from above idiom
Finder() : iterator() { }
Should do the trick. Not providing an argument for a member in the initialization list will call the default constructor on a type that has one, and will zero-initialize POD types including pointers (and it will fail if the type has no default constructor, but that seems unlikely given your scenario).
Related
I am attempting to figure out how to achieve runtime polymorphism with a class called Signal, where its data type is passed as enum value to the constructor. Compile-time polymorphism with templates is not suitable.
As all values in the "signal" are supposed to be of same type, I chose variant-of-vectors instead of vector-of-variants.
enum class Type { UINT8, INT16, FLOAT };
using VariantVector = std::variant<std::vector<uint8_t>, std::vector<int16_t>, std::vector<float>>;
class Signal {
public:
explicit Signal(size_t size, Type type, double value)
: m_size(size), m_type(type) {
// Create variant vector of said type and initialize it with value
}
// Various methods ...
private:
size_t m_size;
Type m_type;
VariantVector m_data; // Variant of vectors
};
I have been able to make most of the things work, but got stuck on how to override the iterator methods. In order to use range-based loops as
Signal signal(100, Type::UINT8, 10);
for(auto& item : signal){
// Do stuff with item
}
the begin() and end() functions need to be defined. I managed to partially solve this with explicit template functions as
template <typename T>
std::vector<T>::iterator begin();
template <typename T>
std::vector<T>::const_iterator begin() const;
template <typename T>
std::vector<T>::iterator end();
template <typename T>
std::vector<T>::const_iterator end() const;
but this does not work for range-based loops (and I'd like to avoid explicit templates anyway).
I tried to implement a couple solutions with std::visit, but did not get far - most solutions were based on operator overloading. Also looked into the double-dispatch visitor pattern, but don't really see how to apply it here.
How to achieve this with a variant of vectors?
Is this even possible or am I attempting to bend some rules of C++ wizardry?
Any insight is more than welcome. Thanks.
EDIT #1:
#Wyck asked in the comments how I'd like range-based loop to work. Ideally I'd like a situation as:
{
Signal signal(100, Type::UINT8, 10);
for(auto& item : signal){
// item is of type uint8&
}
}
{
Signal signal(100, Type::FLOAT, 10);
for(auto& item : signal){
// item is of type float&
}
}
Note the reference to the type, which means changing it should modify the private variant contents of Signal as well.
So, I found it more natural to work in algorithms with collections, not with pair of iterators. So, I wrote some functions like
template <typename R>
void sort(R& range) {
return std::sort(std::begin(range), std::end(range));
}
And to have possibility to work with parts of collections I've wrote following wrapper class, that just holds pair of iterators.
template <typename T>
class Range{
public:
Range(T begin, T end): begin_(begin), end_(end) {}
const T& begin() {
return begin_;
}
const T& end() {
return end_;
}
private:
T begin_, end_;
};
To that point all is fine. Now I want to have function that copies/(moves if possible) its argument and return new collection.
I wrote something like this:
template <typename R>
R sorted(R range) {
sort(range);
return std::move(range);
}
and that's fine except that if I call it with my wrapper Range class internal collection changed. I do understand that with only iterator type it's generally impossible to retrieve the type of collection to create new one, but I want to at least disallow calling it with this Wrapper.
I do understand that I can use static_assert of enable_if to check if it is of particular Range class and I will do that way unless I will find better way. But I want ban it somehow in more general way, so that similar implementation will fail to compile too.
Any ideas?
You can delete the function like:
template <typename T>
void sorted(const Range<T>& range) = delete;
else you can disallow copy and move of the object, so it can only be used with reference
template <typename T>
class Range{
public:
Range(const Range&) = delete;
Range(Range&&) = delete;
Range& operator =(const Range&) = delete;
Range& operator =(Range&&) = delete;
// previous code
};
I would create a traits class called owning_container. By default it considers arguments that are ranges (you should have a traits class/concept constexpr for that -- if begin(x) in a namespace with using std::begin; returns an iterator, call it a range) and have an allocator (another trait) to be owning (as non-owning ranges usually have no need for an allocator) as well as C arrays and std::arrays as owning (via specialization).
This also allows me to detect rvalue owning containers and move their contents in certain contexts (change their iterators into move iterators) without doing the same to non-owning range views.
As mentioned above, a constexpr pseudo-concept might be better than a traits class, or might be useful to augment it.
I'd like to specialize std::iterator_traits<> for iterators of a container class template that does not have the usual nested typedefs (like value_type, difference_type, etc.) and whose source I shouldn't modify. Basically I'd like to do something like this:
template <typename T> struct iterator_traits<typename Container<T>::iterator>
{
typedef T value_type;
// etc.
};
except that this doesn't work, as the compiler is unable to deduce T from Container<T>::iterator.
Is there any working way to achieve the same?
For example:
template <typename T>
class SomeContainerFromAThirdPartyLib
{
typedef T ValueType; // not value_type!
// no difference_type
class iterator
{
typedef T ValueType; // not value_type!
// no difference_type
...
};
iterator begin() { ... }
iterator end() { ... }
...
};
Now suppose I call std::count() using an instance of this class. As far as I know, in most STL implementations, count() returns iterator_traits<Iterator>::difference_type. The primary template of iterator_traits<I> simply does typedef typename I::difference_type difference_type. Same with the other nested types.
Now in our example this obviously won't work, as there's no Container::iterator::difference_type. I thought I could work around this without modifying the iterator class, by specializing iterator_traits for iterators of any Container<T>.
In the end, I just want to be able to use std algorithms like count, find, sort, etc., preferably without modifying any existing code. I thought that the whole point of iterator_traits is exactly that: being able to specify types (like value_type, diff_type etc.) for iterator types that do not support them built-in. Unfortunately I can't figure out how to specialize the traits class for all instances of Container<T>.
Yes. The compiler cannot deduce T from Container<T>::iterator because it is non-deducible context, which in other words means, given Container<T>::iterator, the value of T cannot uniquely and reliably be deduced (see this for detail explanation).
The only solution to this problem is that you've to fully specialize iterator_traits for each possible value of iterator which you intend to use in your program. There is no generic solution, as you're not allowed to edit the Container<T> class template.
Nawaz's answer is likely the right solution for most cases. However, if you're trying to do this for many instantiated SomeContainerFromAThirdPartyLib<T> classes and only a few functions (or an unknown number of instantiations but a fixed number of functions, as might happen if you're writing your own library), there's another way.
Assume we're given the following (unchangeable) code:
namespace ThirdPartyLib
{
template <typename T>
class SomeContainerFromAThirdPartyLib
{
public:
typedef T ValueType; // not value_type!
// no difference_type
class iterator
{
public:
typedef T ValueType; // not value_type!
// no difference_type
// obviously this is not how these would actually be implemented
int operator != (const iterator& rhs) { return 0; }
iterator& operator ++ () { return *this; }
T operator * () { return T(); }
};
// obviously this is not how these would actually be implemented
iterator begin() { return iterator(); }
iterator end() { return iterator(); }
};
}
We define an adapter class template containing the necessary typedefs for iterator_traits and specialize it to avoid problems with pointers:
namespace MyLib
{
template <typename T>
class iterator_adapter : public T
{
public:
// replace the following with the appropriate types for the third party iterator
typedef typename T::ValueType value_type;
typedef std::ptrdiff_t difference_type;
typedef typename T::ValueType* pointer;
typedef typename T::ValueType& reference;
typedef std::input_iterator_tag iterator_category;
explicit iterator_adapter(T t) : T(t) {}
};
template <typename T>
class iterator_adapter<T*>
{
};
}
Then, for each function we want to be able to call with a SomeContainerFromAThirdPartyLib::iterator, we define an overload and use SFINAE:
template <typename iter>
typename MyLib::iterator_adapter<iter>::difference_type
count(iter begin, iter end, const typename iter::ValueType& val)
{
cout << "[in adapter version of count]";
return std::count(MyLib::iterator_adapter<iter>(begin), MyLib::iterator_adapter<iter>(end), val);
}
We can then use it as follows:
int main()
{
char a[] = "Hello, world";
cout << "a=" << a << endl;
cout << "count(a, a + sizeof(a), 'l')=" << count(a, a + sizeof(a), 'l') << endl;
ThirdPartyLib::SomeContainerFromAThirdPartyLib<int> container;
cout << "count(container.begin(), container.end(), 0)=";
cout << count(container.begin(), container.end(), 0) << std;
return 0;
}
You can find a runnable example with the required includes and usings at http://ideone.com/gJyGxU. The output:
a=Hello, world
count(a, a + sizeof(a), 'l')=3
count(container.begin(), container.end(), 0)=[in adapter version of count]0
Unfortunately, there are caveats:
As I said, an overload needs to be defined for each function you plan to support (find, sort, et cetera). This obviously won't work for functions in algorithm that haven't been defined yet.
If not optimized out, there may be small run-time performance penalties.
There are potential scoping issues.
In regards to that last one, the question is in which namespace to put the overload (and how to call the std version). Ideally, it would be in ThirdPartyLib so that it could be found by argument-dependant lookup, but I've assumed we can't change that. The next best option is in MyLib, but then the call has to be qualified or preceded by a using. In either case the end-user should either use using std::count; or be careful about which calls to qualify with std::, since if std::count is mistakenly used with SomeContainerFromAThirdPartyLib::iterator, it will obviously fail (the whole reason for this exercise).
An alternative that I do not suggest but present here for completeness would be to put it directly in the std namespace. This would cause undefined behavior; while it might work for you, there's nothing in the standard that guarantees it. If we were specializing count instead of overloading it, this would be legal.
In the specialization in question, T is in a nondeducible context but there is neither a third party library container code change nor any specialization in the std namespace required.
If the third party library does not provide any free begin and end functions in the respective namespace one can write own functions (into that namespace if desired to enable ADL) and wrap the iterator into an own wrapper class which in turn provides the necessary typedefs and operators.
First one needs the Iterator wrapper.
#include <cstddef>
namespace ThirdPartyStdAdaptor
{
template<class Iterator>
struct iterator_wrapper
{
Iterator m_it;
iterator_wrapper(Iterator it = Iterator())
: m_it(it) { }
// Typedefs, Operators etc.
// i.e.
using value_type = typename Iterator::ValueType;
using difference_type = std::ptrdiff_t;
difference_type operator- (iterator_wrapper const &rhs) const
{
return m_it - rhs.m_it;
}
};
}
Note: It would also be possible to make iterator_wrapper inherit from Iterator, or to make it more generic and have another helper to enable the wrapping of other iterators as well.
Now begin() and end():
namespace ThirdPartyLib
{
template<class T>
ThirdPartyStdAdaptor::iterator_wrapper<typename
SomeContainer<T>::iterator> begin(SomeContainer<T> &c)
{
return ThirdPartyStdAdaptor::iterator_wrapper<typename
SomeContainer<T>::iterator>(c.begin());
}
template<class T>
ThirdPartyStdAdaptor::iterator_wrapper < typename
SomeContainer<T>::iterator > end(SomeContainer<T> &c)
{
return ThirdPartyStdAdaptor::iterator_wrapper < typename
SomeContainer<T>::iterator > (c.end());
}
}
(It is also possible to have them in a different namespace than SomeContainer but loose ADL. IF there are begin and end functions present in the namespace for that container I'd tend to rename the adaptors to be something like wbegin and wend.)
The standard algorithms can be called using those functions now:
ThirdPartyLib::SomeContainer<SomeType> test;
std::ptrdiff_t d = std::distance(begin(test), end(test));
If begin() and end() are included into the library namespace, the container can even be used in more generic contexts.
template<class T>
std::ptrdiff_t generic_range_size(T const &x)
{
using std::begin;
using std::end;
return std::distance(begin(x), end(x));
}
Such code can be used with std::vector as well as ThirdPartyLib::SomeContainer, as long as ADL finds begin() and end() returning the wrapper iterator.
You can very well use the Container as template parameter to your iterator_traits. What matters to the rest of STL are the typedefs inside your traits class, such as value_type. Those should be set correctly:
template <class Container> struct iterator_traits
{
public:
typedef typename Container::value_type value_type;
// etc.
};
You would then use value_type where you would previously use T.
As for using the traits class, you of course parametrize it with the type of your external container:
iterator_traits<TheContainer> traits;
Naturally, this assumes TheContainer is conforms to the common STL containers' contract and has value_type defined correctly.
I'm building a datastructure class with an std-like interface, and implementing different iterators for the data structure.
Conceptually, what I would like to do is something like this:
template <class DataT>
class DataStructure
{
protected:
DataT& Data;
public:
DataStructure(DataT& data) : Data(data) {}
class BaseIterator
{
public:
BaseIterator()
{
cout<<"BaseIterator"<<endl;
}
};
class DerrivedIterator1 : public BaseIterator
{
public:
DerrivedIterator1()
{
cout<<"DerrivedIterator1"<<endl;
}
};
class DerrivedIterator2 : public BaseIterator
{
public:
DerrivedIterator2()
{
cout<<"DerrivedIterator2"<<endl;
}
};
template<class IterT>
IterT Begin()
{
//none-specialized implementation. Possibly throw exception
}
template<>
DerrivedIterator1 Begin<DerrivedIterator1>()
{
//Find beginning for DerrivedIterator1
}
template<>
DerrivedIterator2 Begin<DerrivedIterator2>()
{
//Find beginning for DerrivedIterator1
}
};
But this of course does not compile since C++ doesn't allow to specialize template member functions in none-specialized template containers.
The obvious workaround is of course to declare 2 different functions: Begin_Iterator1 and Begin_Iterator2 and be done with it. But I'm looking for a workaround that doesn't change the interface.
Any ideas?
Edit: I forgot to mention that this is for a HW assignment and so boost and even std is not an option.
Function templates cannot be specialized in C++, point.
It does not matter whether they are members of template or not, specialization of function templates is not allowed. Normally when using argument types to infer the template arguments, overloading does the same specialization would, so specialization for functions (and the associated extra complexity in overload resolution and such) was not deemed necessary.
You however don't have any arguments to infer on and would instantiate the templates manually. No,
DataStructure::DerivedIterator1 i = dataStructure.Begin();
would not work as you wrote the code, because type inference, just like overload resolution is only done on the arguments, not expected return value. You'd have to write:
DataStructure::DerivedIterator1 i = dataStructure.Begin<DataStructure::DerivedIterator1>();
and that has zero benefit over:
DataStructure::DerivedIterator1 i = dataStructure.BeginIterator1();
However, the first expression can be made to work with some wizardry. First you have to define BeginIterator1 and BeginIterator2 and than you'd do a temporary to late-decide which one to construct:
class DataStructure {
...
class BeginIteratorConstructor {
DataStructure &dataStructure;
public:
BeginIteratorConstructor(DataStructure &ds) : dataStructure(ds) {}
operator DerivedIterator1() { return dataStructure.BeginIterator1(); }
operator DerivedIterator2() { return dataStructure.BeginIterator2(); }
};
BeginIteratorConstructor Begin() { return BeginIteratorConstructor(*this); }
...
};
Now dataStructure.Begin() will return a temporary something, that will call BeginIterator1 if you cast it to DerivedIterator1 or call BeginIterator2 when you cast it to DerivedIterator2. If you pass it to something where the compiler can't decide which one to cast to, it will die either because of ambiguous overload or because BeginIteratorConstructor is not in fact iterator and you'll have to cast it explicitly.
(You should carefully make as much of the BeginIteratorConstructor private, but I am not sure how far will the compiler allow you to go, so you'd have to experiment a bit)
You can use a tagging system, which will save you from partially specialized functions inside class templates:
struct base_iter_tag{};
struct der1_iter_tag{};
struct der2_iter_tag{};
template<class T>
struct iter_type;
template<>
struct iter_type<BaseIterator>{
typedef base_iter_tag tag;
};
template<>
struct iter_type<DerivedIterator1>{
typedef der1_iter_tag tag;
};
template<>
struct iter_type<DerivedIterator2>{
typedef der2_iter_tag tag;
};
template<class IterT>
IterT Begin(){
return DoBegin(typename iter_type<IterT>::tag());
}
BaseIterator DoBegin(base_iter_tag){
// ...
}
DerivedIterator1 DoBegin(der1_iter_tag){
// ...
}
DerivedIterator2 DoBegin(der2_iter_tag){
// ...
}
This is essentially what the standard library does with the iterator_traits<T>::iterator_category and overloaded functions depending on the category (e.g. forward_iterator_tag, random_access_iterator_tag, etc...).
The forward declaration of STL library class std::queue is as follows:
namespace std {
template<typename T, class container = deque<T>> class queue
}
That means we can declare an object of type queue with different type specifications like this:
std::queue<float, std::deque<std::string>> string_queue;
Why this is possible? Wouldn't it be much more type safe to declare queue like this:
template<class implementation>
class queue_base
{
private:
implementation m_impl;
/* ----------------------------------------------------------- */
public:
typedef implementation container_type;
typedef typename implementation::size_type size_type;
typedef queue_base<implementation> this_type;
typedef typename implementation::value_type value_type;
/* ----------------------------------------------------------- */
queue_base ();
queue_base (queue_base const& other);
explicit queue_base(container_type const& other);
/* ----------------------------------------------------------- */
value_type& back ();
value_type const& back () const;
bool empty() const;
value_type& front();
value_type const& front() const;
void pop ();
void push (value_type const& value);
size_type size () const;
/* ----------------------------------------------------------- */
}; /* template<class> class queue_base */
/* --------------------------------------------------------------- */
Most implementations of std::queue I have seen implement 'value_type' and 'size_type' in the same manner as you can see in my code above. So, template parameter 'T' is only been used for the default parameter of template parameter 'container' (std::deque).
I mean, I don't think it's "fine" that the float specification in declaration example above is ignored; no matter it works or not.
Wouldn't it be more type safe to declare queue like this:
More type safe yes, but not as convenient. The normal user of queue doesn’t care about the underlying container which is really just an implementation detail. They only care about the element type. This is also for consistency with the other container classes.
Even better would be if the queue class were usable by specifying a class template for the container, as follows:
std::queue<int, std::list> myqueue;
But there’s unfortunately no good, portable way of doing this in C++.
Logically, one might expect something like:
template<typename T, template<typenameU> class C = std::deque>
class queue
{
protected:
C<T> c;
public:
// ...
};
The problem is that std::deque won't match the template
argument, because it is, in fact:
template<typename T, typename Allocator = allocator<T> >
class deque ...
The extra template argument prevents it from working. And if
the extra argument were added to the second parameter of
queue, then most user defined containers couldn't be used,
because they wouldn't have the second argument. The current
solution sidesteps that problem (while still allowing client
code to instantiate std::queue<float>, for example, without
worrying about the underlying container type).
And in the end, why not? Your example of std::queue<float,
std::deque<std::string> > probably won't compile, but what's
wrong with something like std::queue<bool, std::vector<char> >
(avoiding the problematic std::vector<bool>)? As long as
there's an implicit conversion both ways, it's up to the client
to ensure that it does what he wants. (In practice, of course,
it's almost never a problem, because it's rare for client code
to specify the container.)
If you only care about preventing "silly" cases, a simple integrity check is sufficient:
template <typename T, typename Container>
class queue
{
static_assert(std::is_same<T, typename Container::value_type>::value,
"queue require T and Container::value_type to be identical");
};
Or similar facilities in C++03.