I need a 'MultiStack' taking different types of objects, putting each type in a separate stack.
This is what it looks like so far. The open problem is: how to handle the containers for a number of different T
class MultiStack
{
public:
template<typename T>
const T& Get()
{
return Container<T>.back();
}
template<typename T>
void Push( const T& t )
{
Container<T>.push_back( t );
}
template<typename T>
void Pop( const T& /*t*/ )
{
Container<T>.pop_back();
}
private:
// this does not make sense, we obv. need one stack for each T
// template<typename T>
// std::vector<T> Container;
};
Now, I could use the old trick, putting the Container in a member function, like
template<typename T>
auto GetContainer()
{
static std::vector<T> C;
return C;
}
but I don't like this anymore in the age of multi-threading. It is 'dangerous', right!?
Is there a better, elegant way? It is conceivable that I know the allowed types beforehand, if that helps realizing it.
but I don't like this anymore in the age of multi-threading. It is 'dangerous', right!?
Issue is not multi-threading. initialization would be fine.
You still have to protect/synchronize access though, as regular multi-threading code.
Issue is that the container is not per instance of MultiTask, as it is static.
It is mostly as if MultiTask were a Singleton.
It is conceivable that I know the allowed types beforehand, if that helps realizing it.
That helps, you can then use std::tuple, something like (C++14):
template <typename ... Ts>
class MultiStack
{
public:
template<typename T>
const T& Get() const
{
return GetContainer<T>().back();
}
template<typename T>
void Push(const T& t)
{
GetContainer<T>().push_back(t);
}
template <typename T>
void Pop()
{
GetContainer<T>().pop_back();
}
private:
template <typename T>
const std::vector<T>& GetContainer() const { return std::get<std::vector<T>>(Containers); }
template <typename T>
std::vector<T>& GetContainer() { return std::get<std::vector<T>>(Containers); }
private:
std::tuple<std::vector<Ts>...> Containers;
};
Related
I've been working on my archiver, which I had to sort of re-implement recently. It's based on this archiver lib I've found, but also I've had to add support for serialize polymorphic object with their type info. I've been trying to solve this with with utilizing template deduction, but It doesn't seem right. I've learned that using deduction adds the generated methods to overload pool, but I haven't found anything about if you can overload with template definitions.
Here's the code snippet I have:
class Archive {
// ... ctor, and others
// ---
template <class T>
const Archive& operator<<(const T& v) const
{
*this & v;
return *this;
}
template <class T>
Archive& operator>>(T& v)
{
*this & v;
return *this;
}
// ---
template <class T>
Archive& operator&(T*& v)
{
Serializer::LoadObject(v);
return *this;
}
template <class T>
const Archive& operator&(const T*& v) const
{
Serializer::StoreObject(v);
return *this;
}
template <class T>
Archive& operator&(T& v)
{
v.Serialize(*this);
return *this;
}
template <class T>
const Archive& operator&(const T& v) const
{
((T&)(v)).Serialize(*this);
return *this;
}
// ... the rest of the implementation, serializers for POD, arrays and STL containers
};
The basic usage of this is
struct SomePoco{
int m_someMember;
int m_someOtherMember;
template<class AR> void Srerialize(AR&ar){
ar & m_someMember & m_someOtherMember;
}
};
which works fine. If I'd use with pointers of objects, It'd look like this - way oversimplified, don't worry about the cleanness, just for the record:
class SomeSerializableClass : public Serializable{
public:
// ... some macros that adds Serializable implementations
template<class AR> void Srerialize(AR&ar){
ar & m_someMember & m_someOtherMember;
}
private:
int m_someMember;
int m_someOtherMember;
}
SomeSerializableClass *obj = new SomeSerializableClass();
Archive ar;
ar << obj;
// ... rest of the stuff
in this case I'd like to call template <class T> const Archive& Archive::operator&(const T*& v) const insted of template <class T> const Archive& operator&(const T& v) const. The deduction comes this way: template <class T> const Archive& operator&(const T& v) const where T = SomeSerializableClass *
The question is:
- is there any method to override the behaviour of this deduction with custom deduction rule, or
- is there any method to disable deduction for pointers types, so I could define my own operator functions outside of the class?
Update:
I have dug myself through type_trais suggested below and I'm quite not understand something with it. With this type of traits, It doesn't really seem to work on Visual Studio 2017.
template <class T, class = class std::enable_if<std::is_class<T>>::type>
Archive& operator&(T& v)
{
v.Serialize(*this);
return *this;
}
template <class T, class = class std::enable_if<std::is_class<T>>::type>
const Archive& operator&(const T& v) const
{
const_cast<T&>(v).Serialize(*this);
return *this;
}
I've also consulted with the implementation in VS; by spec is_object would be fine for me, because I'm looking for those objects which has their Serialize function, whether they're an instance of a class or struct. However, is_object is a completely different thing in VS, the closes trait was is_class.
Do you guys have any suggestions furthermore?
I am just working on my school homework, and I am interested if C++ could create specialized destructor for pointers. I know that this is not good practice, but because of performance, I want to do it this way. Also because I am curious about it. So lets say, that we have this class:
template<typename T,int(*comp)(const T& first, const T& second)>
class BinomialHeapLite
{
private:
class Node
{
Node* next;
T instance;
}
Node* top;
public:
~BinomialHeapLite();
}
Now I want destructor, that delete just node, if is T only type and delete also inner instance, if is T pointer..
template<typename T, int(*comp)(const T& first, const T& second)>
BinomialHeapLite<T,comp>::~BinomialHeapLite()
{
//some code
delete this->top;
}
template<typename T, int(*comp)(const T* &first, const T* &second)>
BinomialHeapLite<T*,comp>::~BinomialHeapLite()
{
//some code
delete this->top->instance;
delete this->top;
}
But this give me "invalid use of incomplete type". I also want to use pure C++11, because I want to be independent to another libraries (also standards libraries), moreover that libraries are not permitted in out system.
Is something like this possible in pure C++?
You're giving your BinomialHeapLite class a responsibility that it shouldn't have: cleaning up instance if it's a heap-allocated pointer.
That burden should be on the user of your class: what if he is already calling delete in its own code? What if the object is supposed to be reused after your BinomialHeapLite is destroyed?
All your class should do is provide a generic container that manages its own memory. For that task, your should also use smart pointers (std::unique_ptr in this case):
template<typename T,int(*comp)(const T& first, const T& second)>
class BinomialHeapLite
{
private:
class Node
{
std::unique_ptr<Node> next;
T instance;
}
std::unique_ptr<Node> top;
}
You won't need an hand-written destructor then. Refer to the "rule of three/five/zero" for more information.
If you really want to implement your flawed/unconventional design, you could use a partially specialized helper struct that calls delete if its type is a pointer:
template <typename T>
struct dtor_helper
{
static void do_it(T&&){}
};
template <typename T>
struct dtor_helper<T*>
{
static void do_it(T* x){ delete x; }
};
template<typename T, int(*comp)(const T& first, const T& second)>
BinomialHeapLite<T,comp>::~BinomialHeapLite()
{
//some code
dtor_helper<T>::do_it(this->top->instance);
delete this->top;
}
wandbox example
You can not partially specialize a member function. But you can partially specialize a class template:
template <class T>
struct Deallocator{
template <class Node>
static void Deallocate(const Node &node){}
};
template <class T>
struct Deallocator<T *>{
template <class Node>
static void Deallocate(const Node &node){}
};
template<typename T, int(*comp)(const T& first, const T& second)>
BinomialHeapLite<T,comp>::~BinomialHeapLite()
{
//some code
Deallocator<T>::Deallocate(top);
}
Or overload a function :
template<typename T,int(*comp)(const T& first, const T& second)>
class BinomialHeapLite
{
private:
struct Node // a little change here
{
Node* next;
T instance;
};
Node* top;
template <class Ty>
void deallocate(Ty *) {}
template <class Ty>
void deallocate(Ty &) {}
public:
~BinomialHeapLite();
};
template<typename T, int(*comp)(const T& first, const T& second)>
BinomialHeapLite<T,comp>::~BinomialHeapLite()
{
//some code
deallocate(top->instance);
}
I'm having a problem with partial template specialization.
I have this little helper template and partial specialization:
template<typename T>
struct ctor_std_vector_get
{
static_assert(false,"ERROR");
};
template<typename T>
struct ctor_std_vector_get<const std::vector<T>>
{
static const T& get(const T& x){
return x;
}
};
And then, I use it something like this:
template<typename T>
class container
{
public:
container(const std::vector<T>& inp):
{
alloc();
for( const T& t : inp){
const T& x = ctor_std_vector_get<T>::get(t);
}
}
}
But when I compile, I hit the static_assert, when I want the partial specialization. I think I've done something wrong, since if the partial specialization was a match, it would be selected before the base template. What's wrong?
container(const std::vector<T>& inp):
{
alloc();
for( const T& t : inp){
const T& x = ctor_std_vector_get<T>::get(t);
}
}
Let's say you passed a std::vector<int> as a parameter to this function.
Therefore, the T part, in const std::vector<T>& would be int. Simple substitution.
Now that we've established that T is substituted by int, which template do you expect that ctor_std_vector_get<T>, or ctor_std_vector_get<int> wind up using, the default template, or the specialization?
I want to define a templated functor for name comparison, that takes references as well
as pointers. I want to use this for a normal find_if on a container of elements as well as for a container of pointers (unfortunately ptr_vector or the like is not an option).
The best solution I have found so far is the following.
template <typename U>
class by_name{
public:
by_name(U const& pName):mName(pName) {}
template <class T>
typename boost::disable_if_c<boost::is_pointer<T>::value, bool>::type
operator()(T const& pX){ return pX.getName()== mName;}
template <class T>
typename boost::enable_if_c<boost::is_pointer<T>::value, bool>::type
operator()(T pX){ return pX->getName()== mName;}
private:
U mName;
};
This looks quite ugly and very hard to understand for people not knowing enable_if.
Is there an easier way to write such a functor taking pointer and reference alike?
It can be as simple as:
template <class T>
bool operator()(T const& rX) const { return rX.getName() == mName; }
template <class T>
bool operator()(T* const pX) const { return pX->getName() == mName; }
Do the classes that implement getName member functions return anything else than std::string? If not, you can get rid of one template parameter.
This is how I would have implemented the functor:
class by_name
{
public:
by_name(const std::string& name) :
Name(name) {}
template <class T>
bool operator()(T const& pX) const
{
return pX.getName() == Name;
}
template <class T>
bool operator()(T* pX) const
{
if (!pX) // how do you handle a null ptr?
return false;
(*this)(*pX); // #Luc Danton
}
private:
std::string Name;
};
If the pointer version is implemented as
bool operator(T const* pX) const {}
gcc for some reason choose to instantiate
bool operator(T const& pX) const with [T = A*]
The functor has been compiled and tested with gcc 4.6.1.
I've declared a template class MyContainer as bellow, then created an instance of it of type DataType1. The DataType1 class provides a friend function "DataSpecificComparison" which is used by std::sort to compare DataType1 objects. The program compiled and sorted correctly.
I then defined a class called DataType2, gave it a friend implementation of "DataSpecificComparison" and used it to create another instance of MyContainer.
I am now unable to compile the program as a "C2914: 'std::sort' : cannot deduce template argument as function argument is ambiguous" compile time error is reported.
How can a developer specify that the DataSpecificComparison binary predicate is to take arguments of template type T*? Or is there another way around this issue?
template <class T>
class MyContainer
{
private:
vector<T*> m_vMyContainerObjects;
....
public:
....
void SortMyContainerObjects()
{
std::sort(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(), DataSpecificComparison)
}
}
class DataType1
{
....
friend bool DataSpecificComparison(const DataType1 * lhs, const DataType1 * rhs)
}
class DataType2
{
....
friend bool DataSpecificComparison(const DataType2* lhs, const DataType2* rhs)
}
You can use a temporary local function pointer variable of the required type to select the correct overload of DataSpecificComparison:
void SortMyContainerObjects()
{
typedef bool (*comparer_t)(const T*, const T*);
comparer_t cmp = &DataSpecificComparison;
std::sort(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(), cmp);
}
Here the compiler can deduce that you want to use the DataSpecificComparison overload that matches the comparer_t type, which resolves the ambiguity.
sth already gave a correct answer, but there's also a direct alternative based on the same principle:
void SortMyContainerObjects()
{
std::sort(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(),
static_cast<bool (*comparer_t)(const T*, const T*)>(&DataSpecificComparison));
}
This uses essentially the same mechanism. The cast forces overload resolution to happen before the Template Argument Deduction for std::sort.
template<typename T>
struct DataSpecificComp : public binary_function<T, T, bool>
{
public:
bool operator()(const T* lhs, const T* rhs)
{
return *lhs < *rhs;
}
};
call the sort function as shown below:
sort(vi.begin(), vi.end(), DataSpecificComp<int>());
I'd prefer something along the following lines: by default it compares objects with less_than (so you wouldn't have to remember to provide a function with a funny name), and there's an overload that allows giving your own comparison functor (again, value-based):
#include <vector>
#include <algorithm>
#include <functional>
template <class T, class Func>
struct indirect_binary_call_type: public std::binary_function<const T*, const T*, bool>
{
Func f;
indirect_binary_call_type(Func f): f(f) {}
bool operator()(const T* a, const T* b) const
{
return f(*a, *b);
}
};
template <class T, class Func>
indirect_binary_call_type<T, Func> indirect_binary_call(Func f)
{
return indirect_binary_call_type<T, Func>(f);
}
template <class T>
class MyContainer
{
private:
std::vector<T*> m_vMyContainerObjects;
public:
void Sort()
{
Sort(std::less<T>());
}
template <class Func>
void Sort(Func f )
{
std::sort(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(), indirect_binary_call<T>(f));
}
};
int main()
{
MyContainer<int> m;
m.Sort();
m.Sort(std::greater<int>());
}
Did you try defining DataSpecificComparison as template with bunch of specializations and giving it the type?
template<T>
bool DataSpecificComparison(const T* t1, const T* t2)
{
// something non compilable here
}
template<> bool DataSpecificComparison<Data1>(const Data1* t1, const Data1* t2)
{
// return *t1 < *t2;
}
....
void SortMyContainerObjects()
{
std::sort(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(), DataSpecificComparison<T>)
}
....
Templating DataSpecificComparison should work. You can also specifically call the proper std::sort template, but it's a bit cumbersome:
template <class T>
class MyContainer
{
private:
vector<T*> m_vMyContainerObjects;
typedef bool (*compsT)(T, T);
public:
....
void SortMyContainerObjects()
{
std::sort<std::vector<T*>::iterator, compsT>(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(), DataSpecificComparison);
}
}