I am cutting my teeth at some template programming and I am very new to this. What I want to implement are a few CRTP classes that contain an STL container. Let class A{}; serve as an example for the (compile time) base class from which class B{}; and class C{}; are "derived" at compile time following the CRTP style.
Now both B and C will contain containers. For the purpose of the example let it be a std::vector and a std::set respectively. Now, I want to expose the iterators of these via a begin() and an end() function that exposes a forward iterator. However, I do not want to expose what is the exact container that is inside B and C and I want to define these functions for A, so that at call time the correct one for B and C get used.
Is this possible ? Right now my plan is to have a Iterator inner class for B as well as C that will contain the actual iterator of (a vector or a set as the case may be) and delegate the call to it. However this seems to be a lot of replicated glue code and I suspect there is a better option.
I have a couple of questions:
How do I declare the inner clases in A, B and C so that it plays well with CRTP. Do I need to replicate it for A, B and C ? Can it be an empty class in A and I mask them in B and C with specialized implementations ?
How can I expose the iterator with less glue and less duplication ?
I do not want to create dependencies with external libraries like boost and want to stick to std only. So I have to implement whatever extra I need myself. Thanks for all the help.
Expose the iterator too via CRTP:
template <typename T, typename Iter, typename ConstIter>
struct Base
{
Iter begin() { return static_cast<T*>(this)->begin(); }
Iter end() { return static_cast<T*>(this)->end(); }
ConstIter begin() const { return static_cast<const T*>(this)->begin(); }
ConstIter end() const { return static_cast<const T*>(this)->end(); }
};
struct B : Base<B, std::vector<int>::iterator, std::vector<int>::const_iterator>
{
std::vector<int>::iterator begin() { return container.begin(); }
...
private:
std::vector<int> container;
};
If you have more types to expose, then pass a traits class as a template argument to Base:
template <typename T, typename Traits>
struct Base
{
typename Traits::iterator begin() { ... }
...
};
// For this purpose, vector<int> makes a perfect traits class !
struct B : Base<B, std::vector<int> >
{
std::vector<int>::iterator begin() { ... }
...
};
// Here is an example function taking Base as argument
template <typename T, typename Traits>
void foo(const Base<T, Traits>& x)
{
typename Traits::iterator i = x.begin();
...
}
If I understood you corretcly, you are looking for something like this. Note, I made some simple constructor just to illustrate that it works. Also, your class A is mine class TWrapperBase, B - TWrapperB, C - TWrapperC. Another thing, you don't really need to have two derived classes for this particular example, but I assume your classes B and C are significantly different to justify it in your program.
EDIT: Forgot to increment lIterSet in the loop.
#include <vector>
#include <set>
#include <iostream>
template< typename PType, typename PContainer >
class TWrapperBase
{
public:
typedef PType TType;
typedef PContainer TContainer;
typedef typename TContainer::iterator TIterator;
protected:
TContainer mContainer;
public:
TWrapperBase( const TContainer& pOriginal ) :
mContainer( pOriginal )
{
}
TIterator begin( void )
{
return mContainer.begin();
}
TIterator end( void )
{
return mContainer.end();
}
};
template< typename PType, class PContainer = std::vector< PType > >
class TWrapperB : public TWrapperBase< PType, PContainer >
{
public:
TWrapperB( const TContainer& pOriginal ) :
TWrapperBase( pOriginal )
{
}
};
template< typename PType, class PContainer = std::set< PType > >
class TWrapperC : public TWrapperBase< PType, PContainer >
{
public:
TWrapperC( const TContainer& pOriginal ) :
TWrapperBase( pOriginal )
{
}
};
int main( void )
{
int lInit[] =
{
1, 2, 3
};
std::vector< int > lVec( lInit, lInit + 3 );
std::set< int > lSet( lInit, lInit + 3 );
TWrapperB< int > lB( lVec );
TWrapperC< int > lC( lSet );
std::vector< int >::iterator lIterVec = lB.begin();
std::set< int >::iterator lIterSet = lC.begin();
while( lIterVec < lB.end() )
{
std::cout << "vector: " << *lIterVec << " / set: " << *lIterSet << std::endl;
lIterVec++;
lIterSet++;
}
return 0;
}
Related
Is it possible to convert a vector of one type to another implicitly?
i.e some way to make this code work (obviously this is a simplified problem of what I am trying to do)
std::vector<int> intVec;
intVec.push_back(1);
std::vector<double> doubleVec = intVec;
std::vector<double> doubleVec2;
doubleVec2 = intVec;
No, there is no conversion (implicit or otherwise) between different vector types.
You could initialise it from an iterator range:
std::vector<double> doubleVec(intVec.begin(), intVec.end());
perhaps wrapping this in a function:
template <typename To, typename From>
To container_cast(From && from) {
using std::begin; using std::end; // Koenig lookup enabled
return To(begin(from), end(from));
}
auto doubleVec = container_cast<std::vector<double>>(intVec);
template<class T, class A=std::allocator<T>>
struct magic_vector:std::vector<T,A> {
using base=std::vector<T,A>;
using base::base;
magic_vector(magic_vector const&)=default;
magic_vector(magic_vector &&)=default;
magic_vector& operator=(magic_vector const&)=default;
magic_vector& operator=(magic_vector &&)=default;
magic_vector()=default;
template<class U, class B,
class=typename std::enable_if<std::is_convertible<U,T>::value>::type
>
magic_vector( magic_vector<U,B> const& o ):
base( o.begin(), o.end() )
{}
template<class U, class B,
class=typename std::enable_if<
std::is_convertible<U,T>::value
&& noexcept( T(std::declval<U&&>()) )
>::type
>
magic_vector( magic_vector<U,B>&& o ):
base(
std::make_move_iterator(o.begin()),
std::make_move_iterator(o.end())
)
{}
};
magic_vectors are vectors that auto convert from other magic_vectors.
If you have a pointer to a magic_vector that you convert into a pointer to vector, then delete it as a vector, the result is undefined behavior. (However in practice, there will be no harm in every C++ implementation I have checked). This is, however, a strange way to act with vectors.
Replace use of vector with magic_vector. So long as you don't have specializations on the exact type of a container in your code, it should be a drop-in replacement, except now it will auto-convert between them.
Work could be done to have magic_vectors auto-convert with vectors instead of just with magic_vectors.
One way is to create a conversion function. It allows you to express intent at the call site:
#include <iostream>
#include <vector>
template<class To, class From, class Allocator>
std::vector<To, typename Allocator::template rebind<To>::other>
implicit_convert(const std::vector<From, Allocator>& vf)
{
return { std::begin(vf), std::end(vf) };
}
template<class To, class ToA, class From, class FromA>
void implicit_overwrite(std::vector<To, ToA>& to, const std::vector<From, FromA>& from)
{
to.clear();
std::copy(begin(from), end(from), back_inserter(to));
}
int main(int argc, const char * argv[]) {
using namespace std;
std::vector<int> vi { 1, 2 , 3 };
auto vd = implicit_convert<double>(vi);
cout << "after conversion\n";
for (const auto& i : vd) {
cout << i << endl;
}
vi.push_back(4);
implicit_overwrite(vd, vi);
cout << "after copy\n";
for (const auto& i : vd) {
cout << i << endl;
}
return 0;
}
expected output:
after conversion
1
2
3
after copy
1
2
3
4
you could go for something like this (assuming myclass is your class that can be constructed from a std::pair):
#include <iostream>
#include <vector>
#include <utility>
using std::cout;
using std::endl;
class myclass
{
public:
myclass(const std::pair<int, int>& p): first_(p.first), second_(p.second) {}
int first() {return first_;}
int second() {return second_;}
private:
int first_;
int second_;
};
template <class T>
class myvector : public std::vector<T>
{
using base = std::vector<T>;
using base::base;
};
template<>
class myvector<myclass> : public std::vector<myclass>
{
public:
myvector(const std::vector<std::pair<int, int>>& vp):
std::vector<myclass>(vp.begin(), vp.end()) {}
};
int main()
{
std::vector<std::pair<int, int>> vp {{12,3}, {1, 7}};
myvector<myclass> mm = vp;
cout<<mm[0].first(); //prints 12
}
You inherit myvector from std::vector and then you specialize it for myclass. Alternatively you could define myvector in a namespace and access it as mynamespace::vector<myclass>
I have a custom templated container using a map and list being kept in sync. The map needs to hold MyList::const_iterator and the list needs to hold MyMap::const_iterator. The only solution I've been able to find is to pun one of the iterators, as in the example below.
Is there a proper way to forward declare this so that I don't need the ugly punning?
Runnable code available at http://coliru.stacked-crooked.com/a/a5eae03ad5090b27.
(There are definitely other approaches that could be used for the example, but that's out of scope. This is a snippet of a larger program. I'm simply trying to make this "circular" definition without UB.)
#include <iostream>
#include <list>
#include <unordered_map>
template<class ObjectT> class MyClass
{
private:
// SUMMARY: The map must contain an iterator to the list, and the list must contain an iterator to the map.
// I have not been able to figure out how to define that (circular), so I've punned an iterator to a different list for the map entry.
typedef std::list<ObjectT> PunnedList;
struct MapEntry
{
ObjectT m_object;
mutable typename PunnedList::const_iterator m_listIt; // Really a List::const_iterator, but that can't be defined.
};
typedef std::unordered_multimap<std::string, MapEntry> Map;
public:
struct ListEntry
{
typename Map::iterator m_mapIt;
const ObjectT& object() const
{
return m_mapIt->second.m_object;
}
const std::string& name() const
{
return m_mapIt->first;
}
};
private:
typedef std::list<ListEntry> List;
Map mMap;
List mList;
private:
typename List::const_iterator listiter_from_mapiter( typename Map::const_iterator& miter ) const
{
static_assert(sizeof(typename PunnedList::const_iterator) == sizeof(typename List::const_iterator));
return *(reinterpret_cast<typename List::const_iterator*>(&miter->second.m_listIt));
}
public:
typename List::const_iterator append( const std::string &name, const ObjectT& item )
{
static_assert(sizeof(typename PunnedList::const_iterator) == sizeof(typename List::const_iterator));
MapEntry entry{ item, typename PunnedList::const_iterator{} };
auto mapIter = mMap.insert({ name, entry });
mList.push_back({ mapIter });
auto iter = mList.cend();
--iter;
*(reinterpret_cast<typename List::const_iterator*>(&mapIter->second.m_listIt)) = iter;
return iter;
}
typename List::const_iterator begin() const
{
return mList.end();
}
typename List::const_iterator end() const
{
return mList.end();
}
void erase( typename List::const_iterator iter )
{
mMap.erase(iter->m_mapIt);
mList.erase( iter );
}
typename List::const_iterator find( const std::string &name ) const
{
auto range = mMap.equal_range(name);
for (auto mapIter = range.first; mapIter != range.second; ++mapIter)
{
// In the real program, there are additional criteria on the map entry, not needed for the example.
// if (mapIter is a match)
return listiter_from_mapiter(mapIter);
}
return mList.cend();
}
};
int main()
{
MyClass<int> container;
container.append("A",1);
container.append("B",2);
container.append("C",1);
std::cout << container.find("B")->object();
}
it's impossible to declare a type T that depend on a type Y which is also dependent on T. but you can use a wrapper to do that:
(it seems that you want to create a hash table in which elements are in insertion order? a common practice is to wrap the element and an iterator of a linked list.)
#include <string>
#include <list>
#include <unordered_map>
template<typename T>
class A{
struct Wrapper;
typedef std::unordered_multimap<std::string, Wrapper> Map;
typedef typename Map::const_iterator map_iter;
typedef std::list<map_iter> List;
typedef typename List::const_iterator list_iter;
struct Wrapper{
T value;
list_iter iter;
};
Map map;
List list;
public:
// do what you want
};
it works because to declare std::unordered_multimap<std::string, Wrapper>::iterator is not necessary to define Wrapper (needn't to be instantiated here).
Forward-declaring at least one of your inner classes breaks the cycle:
template<class ObjectT> class MyClass
{
public:
struct ListEntry;
private:
typedef std::list<ListEntry> List;
// Rest of the class, using List as you like
Note that the following List::const_iterator works thanks to std::list<T> not requiring T to be complete to be instantiated.
Is it possible to convert a vector of one type to another implicitly?
i.e some way to make this code work (obviously this is a simplified problem of what I am trying to do)
std::vector<int> intVec;
intVec.push_back(1);
std::vector<double> doubleVec = intVec;
std::vector<double> doubleVec2;
doubleVec2 = intVec;
No, there is no conversion (implicit or otherwise) between different vector types.
You could initialise it from an iterator range:
std::vector<double> doubleVec(intVec.begin(), intVec.end());
perhaps wrapping this in a function:
template <typename To, typename From>
To container_cast(From && from) {
using std::begin; using std::end; // Koenig lookup enabled
return To(begin(from), end(from));
}
auto doubleVec = container_cast<std::vector<double>>(intVec);
template<class T, class A=std::allocator<T>>
struct magic_vector:std::vector<T,A> {
using base=std::vector<T,A>;
using base::base;
magic_vector(magic_vector const&)=default;
magic_vector(magic_vector &&)=default;
magic_vector& operator=(magic_vector const&)=default;
magic_vector& operator=(magic_vector &&)=default;
magic_vector()=default;
template<class U, class B,
class=typename std::enable_if<std::is_convertible<U,T>::value>::type
>
magic_vector( magic_vector<U,B> const& o ):
base( o.begin(), o.end() )
{}
template<class U, class B,
class=typename std::enable_if<
std::is_convertible<U,T>::value
&& noexcept( T(std::declval<U&&>()) )
>::type
>
magic_vector( magic_vector<U,B>&& o ):
base(
std::make_move_iterator(o.begin()),
std::make_move_iterator(o.end())
)
{}
};
magic_vectors are vectors that auto convert from other magic_vectors.
If you have a pointer to a magic_vector that you convert into a pointer to vector, then delete it as a vector, the result is undefined behavior. (However in practice, there will be no harm in every C++ implementation I have checked). This is, however, a strange way to act with vectors.
Replace use of vector with magic_vector. So long as you don't have specializations on the exact type of a container in your code, it should be a drop-in replacement, except now it will auto-convert between them.
Work could be done to have magic_vectors auto-convert with vectors instead of just with magic_vectors.
One way is to create a conversion function. It allows you to express intent at the call site:
#include <iostream>
#include <vector>
template<class To, class From, class Allocator>
std::vector<To, typename Allocator::template rebind<To>::other>
implicit_convert(const std::vector<From, Allocator>& vf)
{
return { std::begin(vf), std::end(vf) };
}
template<class To, class ToA, class From, class FromA>
void implicit_overwrite(std::vector<To, ToA>& to, const std::vector<From, FromA>& from)
{
to.clear();
std::copy(begin(from), end(from), back_inserter(to));
}
int main(int argc, const char * argv[]) {
using namespace std;
std::vector<int> vi { 1, 2 , 3 };
auto vd = implicit_convert<double>(vi);
cout << "after conversion\n";
for (const auto& i : vd) {
cout << i << endl;
}
vi.push_back(4);
implicit_overwrite(vd, vi);
cout << "after copy\n";
for (const auto& i : vd) {
cout << i << endl;
}
return 0;
}
expected output:
after conversion
1
2
3
after copy
1
2
3
4
you could go for something like this (assuming myclass is your class that can be constructed from a std::pair):
#include <iostream>
#include <vector>
#include <utility>
using std::cout;
using std::endl;
class myclass
{
public:
myclass(const std::pair<int, int>& p): first_(p.first), second_(p.second) {}
int first() {return first_;}
int second() {return second_;}
private:
int first_;
int second_;
};
template <class T>
class myvector : public std::vector<T>
{
using base = std::vector<T>;
using base::base;
};
template<>
class myvector<myclass> : public std::vector<myclass>
{
public:
myvector(const std::vector<std::pair<int, int>>& vp):
std::vector<myclass>(vp.begin(), vp.end()) {}
};
int main()
{
std::vector<std::pair<int, int>> vp {{12,3}, {1, 7}};
myvector<myclass> mm = vp;
cout<<mm[0].first(); //prints 12
}
You inherit myvector from std::vector and then you specialize it for myclass. Alternatively you could define myvector in a namespace and access it as mynamespace::vector<myclass>
I have some conceptual problem in a class hierarchy, where the Base class depends on a fixed scalar type T, but the derived CRTP'ed classes use return value type deduction.
For example, consider the following class hierarchy:
template<typename ... Args> struct VectorBase;
template<typename T>
struct VectorBase<T>
{
virtual T eval(int) const = 0;
auto operator[](int i) {return this->eval(i);}
};
template<typename T, typename Derived>
struct VectorBase<T, Derived> : public VectorBase<T>
{
virtual T eval(int i) const override final { return this->operator[](i); }
auto operator[](int i) const
{
return static_cast<Derived const&>(*this).operator[](i);
}
};
template<typename T>
struct Vector : public VectorBase<T, Vector<T> >
{
//just for code shortness,
//in reality there is a container which returns the corresponding elements
auto operator[](int i) const { return T{}; }
};
template<typename VectorType>
struct SomeTransformation : public VectorBase< /* ... what to write here generically? */ double, SomeTransformation<VectorType> >
{
VectorType const& v;
SomeTransformation(VectorType const& _v) : v(_v) {}
auto operator[](int i) const
{
//do something with vector v and return i-th element, e.g.
return v[i]*0.1;
}
};
DEMO
Now, given a specific vector with value type int, say, one can apply SomeTransformation and get a vector of value type double. Moreover, I can be sure that SomeTransformation derives from VectorBase<double>, so that, for example, I can't falsely assign it to a VectorBase<int>-pointer:
int main()
{
Vector<int> v;
std::cout<<typeid(decltype(v[0])).name()<<std::endl; //prints "i" for int
auto u = SomeTransformation<decltype(v)>(v);
std::cout<<typeid(decltype(u[0])).name()<<std::endl; //prints "d" for double
//works
std::unique_ptr<VectorBase<double> > ud = std::make_unique<SomeTransformation<decltype(v)> >(v);
//gives a compile-time error, which is good
//std::unique_ptr<VectorBase<int> > ui = std::make_unique<SomeTransformation<decltype(v)> >(v);
}
Now for the problem: in the scalar type argument of SomeTransformation, where I wrote /* ... what to write here generically? */, I really would want to write something like
template<typename VectorType>
struct SomeTransformation :
public VectorBase<decltype(std::declval<SomeTransformation<VectorType> >().operator[](0)), SomeTransformation<VectorType> >
{
//...
};
in order to deduce the value type of the transformation automatically and propagate this type down to the base class. However, this doesn't seem to work, which I think is because the base classes are instantiated before the derived class ... so the class of which I want to deduce the type doesn't exists yet.
Is there any way to obtain this behaviour without breaking the inheritance hierarchy?
I figured out a possible alternative by myself and want to bring it up for discussion.
One could for instance add a type parameter T also to the derived class and then use a dummy type in order to instantiate this class once. With this, it is possible to deduce the return type of the so-created class, which is used in a next step to instantiate the class to be really used.
Example:
namespace detail
{
template<typename T, typename VectorType>
struct SomeTransformation :
public VectorBase<T, SomeTransformation<T, VectorType> >
{
//the same as above
};
}
struct DummyType
{
//make any type convertible to DummyType
template<typename T> DummyType(T const&) {}
};
template<typename VectorType>
using SomeTransformationValueType =
decltype(std::declval<detail::SomeTransformation<DummyType, VectorType> >().operator[](0));
template<typename VectorType>
using SomeTransformation =
typename detail::SomeTransformation<SomeTransformationValueType<VectorType>, VectorType>;
DEMO
Let's say I'd like to write an algorithm that prints the value of each element in a container. The container could be a Sequence or Associative container (e.g. std::vector or std::map). In the case of a sequence, the algorithm would print the value_type. In the case of an associative type, the algorithm would print the data_type. How can I write my algorithm (only once!) so that it works with either one? Pretend that the algorithm is complex and that I don't want to repeat it for both sequence/associative versions.
For example:
template <class Iterator>
void printSequence(Iterator begin, Iterator end)
{
for (Iterator it=begin; it!=end; ++it)
std::cout << *it;
}
template <class Iterator>
void printAssociative(Iterator begin, Iterator end)
{
for (Iterator it=begin; it!=end; ++it)
std::cout << it->second;
}
template <class Iterator>
void printEither(Iterator begin, Iterator end)
{
// ????
}
The difference that you have between your two function templates is not a difference between associative containers and sequences but a difference in the part of the type that is stored.
To clarify, std::set is an associative container but would work with your printSequence function; the problem with map is not the fact that it is associative, but that the value_type is a pair an you are only interested on the second part.
The simplest thing to do is to abstract the dereferencing operation.
E.g. used like this:
#include <map>
#include <vector>
template< class X, class Y >
void test( const std::map<X, Y>& mp )
{
printEither( mp.begin(), mp.end(), MakeMapDerefence( mp ) );
}
template< class Y >
void test( const std::vector<Y>& vec )
{
printEither( vec.begin(), vec.end(), MakeSimpleDereference( vec ) );
}
Defined like this (there's a fair bit of boiler plate that's probably a boost one-liner):
template< class ReferenceType, class IteratorType >
struct SimpleDereference
{
ReferenceType operator() ( IteratorType i ) const
{
return *i;
}
};
template< class ReferenceType, class IteratorType >
struct MapDereference
{
ReferenceType operator() ( IteratorType i ) const
{
return i->second;
}
};
// Helper template function to make an appropriate SimpleDerefence instance
template< class Container >
SimpleDereference< typename Container::const_reference
, typename Container::const_iterator >
MakeSimpleDereference( const Container& )
{
return SimpleDereference< typename Container::const_reference
, typename Container::const_iterator >();
}
// Helper template function to make an appropriate SimpleDerefence instance
template< class Container >
SimpleDereference< typename Container::reference
, typename Container::iterator >
MakeSimpleDereference( Container& )
{
return SimpleDereference< typename Container::reference
, typename Container::iterator >();
}
// Helper template function to make an appropriate MapDerefence instance
template< class Container >
MapDereference< const typename Container::mapped_type&
, typename Container::const_iterator >
MakeMapDerefence( const Container& )
{
return MapDereference< const typename Container::mapped_type&
, typename Container::const_iterator >();
}
// Helper template function to make an appropriate MapDerefence instance
template< class Container >
MapDereference< typename Container::mapped_type&
, typename Container::iterator >
MakeMapDereference( Container& )
{
return MapDereference< typename Container::mapped_type&
, typename Container::iterator >();
}
#include <iostream>
#include <ostream>
template <class Iterator, class Dereference> void printEither(Iterator begin, Iterator end, Dereference deref)
{
for (; begin != end; ++begin)
{
std::cout << deref(begin);
}
}
I've whipped up an iterator adapter based on Charles' answer. I'm posting it here in case anyone finds it useful:
#include <iostream>
#include <map>
#include <vector>
#include <boost/iterator/iterator_adaptor.hpp>
//------------------------------------------------------------------------------
template <class Iterator>
void print(Iterator begin, Iterator end)
{
for (Iterator it=begin; it!=end; ++it)
std::cout << *it << "\n";
}
//------------------------------------------------------------------------------
template <class BaseIterator>
class MapDataIterator :
public boost::iterator_adaptor<
MapDataIterator<BaseIterator>,
BaseIterator,
typename BaseIterator::value_type::second_type >
{
public:
typedef typename BaseIterator::value_type::second_type& reference;
MapDataIterator() {}
explicit MapDataIterator(BaseIterator base)
: MapDataIterator::iterator_adaptor_(base) {}
private:
friend class boost::iterator_core_access;
reference dereference() const
{return this->base_reference()->second;}
};
//------------------------------------------------------------------------------
int main()
{
std::vector<int> vec;
vec.push_back(31);
vec.push_back(41);
std::map<int,int> map;
map[31] = 41;
map[59] = 26;
typedef MapDataIterator< std::map<int,int>::iterator > DataIter;
print( vec.begin(), vec.end() );
print( DataIter(map.begin()), DataIter(map.end()) );
}
This solution has the added advantage that the algorithm need not be aware of how to dereference the iterators. It is also reusable for any existing algorithm that expects a "data sequence".
I'm surprised this little critter doesn't already exist in Boost.