I would like to convert a parameter pack of iterator types into the corresponding parameter pack of references. This is what I've got so far:
template <class Iterator, class... Iterators>
class cast_iterators_to_references
{
using head_reference_type = std::iterator_traits<Iterator>::reference
// TODO
//using type = ;
};
Where do I take it from here?
The reason I'm doing this is to create a "view" object. It contains a tuple of iterators to the containers it's referencing. I'd like to have a method that returns a tuple of the elements at some index so that I can create a custom iterator for it, create begin and end methods, and use it in a range-based for statement.
Here's how it could be used:
template<class Iterators...>
tuple_iterator
{
public:
using tuple_type = std::tuple<Iterators...>;
using references = cast_iterators_to_references<Iterators...>;
using tuple_element_type = std::tuple<references>;
// ... construct from tuple, copy/move constructors, copy/move assignment etc.
tuple_element_type operator[](size_t index)
{
tuple_element_type element;
for (size_t i = 0; i < sizeof...(Iterators); i++)
std::get<i>(element) = std::get<i>(data_)[offset_ + index];
return element;
}
// ... increment, decrement operators etc.
private:
tuple_type data_;
size_t offset_;
}
Parameter packs are not first-class, so they are a bit fiddly to handle.
A first stab at the cast_iterators_to_references metafunction could be this :
// Not defined, used to wrap a pack into a type
template <class...> struct pack;
template <class... Iterators>
using cast_iterators_to_references = pack<
typename std::iterator_traits<Iterators>::reference...
>;
But then you need helper classes to unpack the pack via pattern-matching :
template <class> unpack_to_tuple;
template <class... Ts> unpack_to_tuple<pack<Ts...>> {
using type = std::tuple<Ts...>;
};
// In your class
using references = cast_iterators_to_references<Iterators...>;
using tuple_element_type = typename unpack_to_tuple<references>::type;
So you're probably better off using the parameter pack directly :
using tuple_element_type = std::tuple<
typename std::iterator_traits<Iterators>::reference...
>;
Your operator[] can be written as follows :
template <std::size_t... Idx>
auto access(size_t index, std::index_sequence<Idx...>) {
return std::tie(std::get<Idx>(data_)[index + offset_]...);
}
tuple_element_type operator[](size_t index)
{
return access(index, std::index_sequence_for<Iterators...>{});
}
Related
It there a way to change the data stored inside a std::vector inside a const function? See the following code to understand what I want to accomplish:
// class holding properties and data
class Output{
public:
int * values; // possibility 1: raw pointer
std::vector<int> vc; // possibility 2: std::vector
mutable std::vector<int> vm; // possibility 3: mutable vector
//std::vector<mutable int> vm; something like this,
};
class Node{
Output out;
void test()const{
// i want to change the "data" of the Output but not the Object
out.values[0] = 0;//works: i can change the output data
out.values = nullptr;//works: compile error, i cant change the pointer
out.vc[0] = 1; // compile error, not possible :(
out.vm[0] = 1; // that is what i want
out.vm.resize(3); // this is now possible, but should be not possible
}
};
I can use a raw pointer to achieve my goal, but i would prefer a std::vector if this is possible.
A mutable content vector may looks like this:
template<typename T>
class mutable_vector : public std::vector<T>{
public:
T& operator[](int index)const{
return const_cast<mutable_vector<T>*>(this)->data()[index];
}
typename std::vector<T>::iterator begin()const{
return const_cast<mutable_vector<T>*>(this)->begin();
}
typename std::vector<T>::iterator rbegin()const{
return const_cast<mutable_vector<T>*>(this)->rbegin();
}
};
I am trying to store the parameter pack of lvalue references of a variadic template for later use.
I have the following working for now.
template <typename... Ts>
class Foo {
private:
std::tuple<Ts...> m_args;
public:
template<typename... Args>
Foo(Args&&... args) : m_args(std::make_tuple(std::forward<Args>(args)...))
{
}
};
int main() {
int x = 10;
int y = 20;
Foo<int, int> foo(x, y);
}
However, I would like to store the parameter pack as a reference so that I can access the same object later.
I am not sure how I can do that. Any help would be appreciated.
The best I can imagine, is the use of std::forward_as_tuple.
Unfortunately I don't see a way to use it with perfect forwarding: if you want register values in a tuple inside a class, you have to decide the type of the tuple one time for all.
The best I can imagine is a tuple of const references; something as follows
template <typename ... Ts>
class Foo
{
private:
std::tuple<Ts const & ...> m_args;
public:
Foo (Ts const & ... as) : m_args{std::forward_as_tuple(as...)}
{ }
};
I hope isn't necessary remember you how dangling references can be dangerous for a solution based on a tuple of references.
Hi I am trying to create an object of type T where T is a pointer via the use of T result = T(). But instead of calling the constructor it simply returns a null pointer.
Here is an example of some affected code:
template <class T>
T readBlockchain(std::ifstream* stream) {
T result = T(); // Result is null after this
decltype(result->getLastBlock()) blkPtr = result->getLastBlock();
auto blk = *blkPtr;
decltype(result->getLastBlock()) lastBlock = &readBlock<decltype(blk)>(stream);
if(!lastBlock->verify())
return nullptr;
unsigned long count = *readUnsignedLong(stream);
unsigned long orphanCount = *readUnsignedLong(stream);
std::map<std::string, decltype(blk)> blocks = std::map<std::string, decltype(blk)>();
for(int i = 0; i < count - 1; i++){
decltype(blk) block = readBlock<decltype(blk)>(stream);
if(!block.verify())
return nullptr;
blocks.insert(std::make_pair(block.getHash(), block));
}
std::vector<Blockchain<decltype(blk)>*> orphanedChains = std::vector<Blockchain<decltype(blk)>*>();
for(int i = 0; i < orphanCount - 1; i++){
Blockchain<decltype(blk)>* orphan = &readOrphanedChain<Blockchain<decltype(blk)>>(stream);
orphanedChains.push_back(orphan);
}
result->setLastBlock(lastBlock);
result->setCount(count);
result->setOrphanCount(orphanCount);
result->setBlocks(blocks);
result->setOrphanedChains(orphanedChains);
return result;
}
If my understanding is correct. In order to generalize your readBlockchain correctly, you would want when T is a pointer to create a new object of T in the heap and when T is a concrete type to create a regular T object by calling the constructor of T. One solution would be to use the following specialization construct.
template<typename T>
struct CreateNew {
template<typename... Args>
static T apply(Args&&... args) { return T(std::forward<Args>(args)...); }
};
template<typename T>
struct CreateNew<T*> {
template<typename... Args>
static decltype(auto) apply(Args&&... args) { return std::make_unique<T>(std::forward<Args>(args)...); }
};
That is, you could create a template class that takes a template argument T along with a specialization of that template class for pointers of type T*. Inside the primary template (e.g., static member function apply) you'll create objects of type T by calling the constructor of class T and inside the specialization you'll create heap objects of T* (Notice that in the specialization I return a std::unique_ptr<T*> for convenience).
Thus, your readBlockChain template function would become:
template <class T>
decltype(auto) readBlockchain(std::ifstream* stream) {
auto result = CreateNew<T>::apply(/* T constructor arguments */);
...
return result;
}
Live Demo
I am storing a collection of std::vectors in a std::tuple. However, when I get an element from the tuple and modify it, I am only modifying a copy of the element returned.
template<typename... Ts>
class ComponentStore
{
public:
ComponentStore()
{
}
~ComponentStore()
{
}
template<typename T>
std::vector<T>& Get()
{
return std::get<std::vector<T>>(m_components);
}
private:
std::tuple<std::vector<Ts>...> m_components;
};
This is how I plan to use the ComponentStore class:
ecs::component::ComponentStore<ecs::component::Position, ecs::component::Velocity> comstore;
//Get the position vector
auto positionvec = comstore.Get<ecs::component::Position>();
//Add a new position
positionvec.emplace_back(ecs::component::Position{});
//Later on, get the position vector again
auto positionvec2 = comstore.Get<ecs::component::Position>();
//But it's empty??? this is wrong. It should have 1 element.
by using auto by itself, you create a variable of the deduced non-reference type, so
auto positionvec = comstore.Get<ecs::component::Position>();
creates a new vector;
you can fix this by using auto&:
auto& positionvec = comstore.Get<ecs::component::Position>();
I'm building a large project on Debian 6.0.6 (with gcc 4.4.5) that was initially built in Microsoft VS (2008, I think).
What seems to be the problem is that when I declare a member as
typedef typename std::set<T>::iterator iterator, and then later use this iterator, gcc appears to interpret this as (const T*).
The part of the class containing the typename designation:
template <class entityType>
class entityArray
{
private: std::set<entityType> m_array;
public: typedef typename std::set<entityType>::iterator iterator;
...
public:
entityType* At( const char* name);
...
};
plus a few other classes that are needed for the discussion:
class entity
{
private:
entity* m_parent;
int m_ncid;
std::string m_name;
public:
entity () { m_ncid = 0; m_parent = NULL;}
virtual ~entity () {};
...
};
class attribute : public entity
{
public:
attribute(){};
virtual ~attribute(){};
};
class var : public entity
{
private:
entityArray<attribute> m_atts;
public:
var(){}
virtual ~var(){}
...
};
class dim : public entity
{
public:
dim() {};
virtual ~dim() {};
};
class group : public entity
{
private:
entityArray<var> m_vars;
entityArray<dim> m_dims;
...
public:
dim* DimAt( const char* dimname ) { return m_dims.At(dimname);}
};
Now an iterator is initialized through a call to the function DimAt which in turn calls At. The At function in the first class is defined as:
template <class entityType>
entityType* entityArray<entityType>::At( const char* name )
{
entityType dummy;
iterator iter;
entityType* ptr;
... define dummy ...
iter = m_array.find( dummy );
ptr = (iter != m_array.end()) ? &(*iter) : NULL;
return ptr;
}
Compiling the above produces
error: invalid conversion from const dim* to dim*., referring to &(*iter).
I realize that typename is required for declaring iterator, since the type is a dependent and qualified name, but I don't see why this substitution (const *) is being performed by the compiler. I would appreciate any help that you could provide. Thanks!
This has absolutely nothing to do with typename.
The standard allows std::set<T>::iterator and std::set<T>::const_iterator to be the same type, and with GCC the types are the same.
The reason is that modifying an element of a std::set e.g. by *iter = val might invalidate the ordering of the set elements, breaking the invariant that the elements of the set are always in order. By making the iterator type a constant iterator instead of a mutable iterator it's not possible to alter the element, preventing you from corrupting the set's ordering.
So with GCC's implementation, when you dereference the iterator using *iter you get a const entitType& and when you take its address using &*iter you get a const entityType*