This toes a fine line between answering your question and providing a solution to your problem but not directly answering your question, but I think you may find this helpful.
For background, check out this question. The author mentions that he didn't like Boost's solution, and I didn't particularly like the one proposed there either. I was writing a quick & dirty serialization library (think python's marshal) where you would call serialize(object, ostream)
on an object to serialize it. I realized I wanted this function call to one of four things:
- If
object
is plain old data, just write out the size and raw data
- If
object
is a class that I've created with its own member function (object::serialize
), then call that member function
- If there's a template specialization for that type, use it.
- If none of the above is true, throw a compilation error; the serialize function is being used improperly.
When I code, I try to avoid stuff that is 'tricky' or hard to understand at a glance. I think this solution solves the same problem without using code that must be pondered for hours to understand:
#include <type_traits>
#include <iostream>
#include <vector>
#include <string>
// Template specialization for a POD object
template<typename T>
typename std::enable_if< std::is_pod<T>::value, bool>::type
serial(const T &out, std::ostream &os)
{
os.write((const char*) &out, sizeof(T));
return os.good();
}
// Non POD objects must have a member function 'serialize(std::ostream)'
template<typename T>
typename std::enable_if< ! std::is_pod<T>::value, bool>::type
serial(const T &out, std::ostream &os)
{
return out.serial(os);
}
// Additional specializations here for common container objects
template<typename T>
bool serial(const std::vector<T> &out, std::ostream &os)
{
const size_t vec_size = out.size();
if(!serial(vec_size, os))
return false;
for(size_t i =0; i < out.size(); ++i)
{
if(!serial(out[i], os))
return false;
}
return true;
}
class SomeClass
{
int something;
std::vector<double> some_numbers;
...
bool serial(std::ostream &os)
{
return serial(something, os) && serial(some_numbers, os);
}
};
If you can boil down your needs to a simple set of rules, and can live with a slightly less general solution, I think this method works well.