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?
Related
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;
};
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 have a mechanism that uses function overloads to decompose a type into primitives. Here is a sample of the mechanism:
template <typename M, typename T> void process(M&, T&);
template <typename M, typename T>
void process_impl(M& m, const T& t) {
m.write(t);
}
template <typename M, typename T>
void process_impl(M& m, const std::vector<T>& v) {
for (const auto& t: v) {
process(m, t);
}
}
template <typename M, typename T>
void process(M& m, const T& t) {
process_impl(m, t);
}
The use case is to feed a type to process(), which will decompose it into simple types using the overloads of process_impl(). In order to customize the behavior of process() for a specific type, simply overload process():
struct media {
template <typename T> void write(const T& t) { std::cout << t << std::endl; }
};
void process(media& m, const std::string& s) {
process(m, s.size());
}
This code:
media m;
process(m, std::vector<std::string>{"1", "22"});
Outputs:
1
2
Now, I want to wrap media in a class, such that I can further tweak the behavior of process() for my wrapper structure, but I want to preserve the initial behavior of process() regarding media:
template <typename M>
struct debug_media {
template <typename T> void write(const T& t) { m.write(t); }
M m;
};
template <typename M, typename T>
void process(debug_media<M>& d, const T& t) {
std::cout << "debug: ";
process(d.m, t);
}
Ideally, I want the output to be:
debug: 1
debug: 2
But that is not the case, since the overload for debug_media is used only once, for the first invocation; afterward, the overloads of process() that accept a media are used, not the one with debug_media<media>.
I cannot have inheritance between media and debug_media. Is it possible to preserve the behavior of both overloads?
I have put sample code on ideone.
You can add the extra overload:
template <typename M, typename T> void process(debug_media<M>& d, const std::vector<T>& v)
{
for(const auto& t : v) {
process(d, t);
}
}
Live example
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 need to define a get method in two different ways. One for simple types T. And once for std::vector.
template<typename T>
const T& Parameters::get(const std::string& key)
{
Map::iterator i = params_.find(key);
...
return boost::lexical_cast<T>(boost::get<std::string>(i->second));
...
}
How can I specialize this method for std::vector. As there the code should look something like this:
template<typename T>
const T& Parameters::get(const std::string& key)
{
Map::iterator i = params_.find(key);
std::vector<std::string> temp = boost::get<std::vector<std::string> >(i->second)
std::vector<T> ret(temp.size());
for(int i=0; i<temp.size(); i++){
ret[i]=boost::lexical_cast<T>(temp[i]);
}
return ret;
}
But I do not know how to specialize the function for this. Thanks a lot.
Don't specialize function template.
Why Not Specialize Function Templates?
Template Specialization and Overloading
Instead, use overload.
Write a function template get_impl to handle the general case, and overload (not specialize) this to handle the specific case, then call get_impl from get as:
template<typename T>
const T& Parameters::get(const std::string& key)
{
//read the explanation at the bottom for the second argument!
return get_impl(key, static_cast<T*>(0) );
}
And here goes the actual implementations.
//general case
template<typename T>
const T& Parameters::get_impl(const std::string& key, T*)
{
Map::iterator i = params_.find(key);
return boost::lexical_cast<T>(boost::get<std::string>(i->second));
}
//this is overload - not specialization
template<typename T>
const std::vector<T>& Parameters::get_impl(const std::string& key, std::vector<T> *)
{
//vector specific code
}
The static_cast<T*>(0) in get is just a tricky way to disambiguate the call. The type of static_cast<T*>(0) is T*, and passing it as second argument to get_impl will help compiler to choose the correct version of get_impl. If T is not std::vector, the first version will be chosen, otherwise the second version will be chosen.
Erm. call it something else? e.g.
template<typename T>
const T& Parameters::getVector(const std::string& key)
{
Map::iterator i = params_.find(key);
std::vector<std::string> temp = boost::get<std::vector<std::string> >(i->second)
// T is already a vector
T ret; ret.reserve(temp.size());
for(int i=0; i<temp.size(); i++){
ret.push_back(boost::lexical_cast<typename T::value_type>(temp[i]));
}
return ret;
}
You'll have to call this as:
foo.getVector<std::vector<int> > ("some_key");
Nothing in your question precludes this.
Now, if you really do need to use get(), then you have to rely on partially specializing a structure, as function partial specialization is not supported by the language.
This is a lot more complicated, for example:
template <typename T>
struct getter
{
const T& operator()(std::string const& key)
{
// default operations
}
};
// Should double check this syntax
template <typename T>
struct getter<std::vector<T, std::allocator<T> > >
{
typedef std::vector<T, std::allocator<T> > VecT;
const VecT& operator()(std::string const& key)
{
// operations for vector
}
};
Then in you method becomes:
template<typename T>
const T& Parameters::get(const std::string& key)
{
return getter<T>()(key); // pass the structures getter needs?
}