C++ - boost::any serialization - c++

As far as I understand, there is no serialization (boost::serialization, actually) support for boost::any placeholder.
Does someone know if there is a way to serialize a custom boost::any entity?
The problem here is obvious: boost::any uses template-based placeholders to store objects and typeid to check if boost::any_cast is appropriate.
So, there is a custom abstract superclass placeholder and custom template-based derived classes, which are created the following way:
template <T> custom_placeholder : public placeholder {
virtual std::type_info type() const { return typeid(T); }
virtual ...
};
Obviously, this brings some troubles when even thinking about serializing this stuff. Maybe someone knows some trick to make such kind of serialization (and of course, proper deserialization)?
Thank you

If you want to stick with boost::any i am not sure but you can write your own "boost::any". I'm using this code for proxy methods to pass the parameters.
#include <iostream>
#include <boost\smart_ptr\scoped_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/serialization/access.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/export.hpp>
#include <sstream>
class my_placeholder
{
public:
virtual ~my_placeholder(){}
my_placeholder(){}
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
// serialize base class information
//ar & boost::serialization::base_object<bus_stop>(*this);
//ar & m_placeholder;
}
};
template<typename T>
class my_derivedplaceholder:
public my_placeholder
{
public:
my_derivedplaceholder()
{
}
my_derivedplaceholder(T &value)
{
m_value=value;
}
T m_value;
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
// serialize base class information
ar & boost::serialization::base_object<my_placeholder>(*this);
ar & m_value;
}
};
BOOST_CLASS_EXPORT_GUID(my_derivedplaceholder<int>, "p<int>");
class my_any
{
public:
my_any()
{
}
template<typename T>
my_any(const T &value)
{
m_placeholder.reset(new my_derivedplaceholder<T>(const_cast<T&>(value)));
}
template<typename T>
void operator=(const T &value)
{
m_placeholder.reset(new my_derivedplaceholder<T>(const_cast<T&>(value)));
}
protected:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
// serialize base class information
//ar & boost::serialization::base_object<bus_stop>(*this);
ar & m_placeholder;
}
template<typename T>
friend T my_anycast(my_any &val);
boost::shared_ptr<my_placeholder> m_placeholder;
};
template<typename T>
T my_anycast(my_any &val)
{
boost::shared_ptr<my_derivedplaceholder<T>> concrete=boost::dynamic_pointer_cast<my_derivedplaceholder<T>>(val.m_placeholder);
if (concrete.get()==NULL)
throw std::invalid_argument("Not convertible");
return concrete->m_value;
}
void main()
{
my_any m=10;
int a=my_anycast<int>(m);
std::cout << a << std::endl;
std::stringstream ss,ss2;
boost::archive::text_oarchive oa(ss);
oa << m;
boost::archive::text_iarchive ia(ss);
my_any m2;
ia >> m2;
std::cout << my_anycast<int>(m2) << std::endl;
}

It is not possible at all, at least for arbitrary types. Note that maybe you could serialize using some tricky code (like finding the size of the elements contained in the any), but the any code relies on the compiler statically putting the any type_code and the proper types inside the placeholder. You surely cannot do that in deserialization in C++, as the type that you'd get from the deserialization is not known at compile time (as required by the newly formed boost::any).
The best solution is to build some kind of specialized any type for the exact types of elements you're going to serialize. Then, you can have special cases for the actual type of element being deserialized, but note that each element type serialization/deserialization has to be phisically written as static C++ code.
PD. Some others suggested using boost::variant as a representation of this specialized type holding the exact types you're going to serialize. You need a way of discerning the exact type on deserialization, though (maybe assigning identifiers to types in the variant).

Assuming you have to use boost::any and you cannot switch to variant, a map<type_info const*, string(*)(any)> based solution could get you done.
You have to initialize at runtime such a map with all the types you plan to use. Of course, you can use something along the lines of
template <typename T>
struct any_serializer
{
static string perform(any a)
{
T const& x = any_cast<T const&>(a);
stringstream out;
out << x;
return out.str();
}
};
and populate the map with addresses of any_serializer<T>::perform under the key &typeid(T). You can specialize the class any_serializer and use some (ugly) macros to populate the map.
More difficult is of course the deserialization. I haven't had a look at boost::lexical_cast for a while, perhaps it can provide some help. I am afraid that this is totally problem-dependant. However, you only need one function, which takes a string and returns one any. You may also want to prepend your output string with a custom type identifier.

There is no need to create new class. Try to use xany https://sourceforge.net/projects/extendableany/?source=directory
xany class allows to add new methods to any's existing functionality. By the way there is a example in documentation which does exactly what you want.

Related

Creating custom boost serialization output archive

I'm trying to use Boost serialization to serialize objects into a buffer. The objects are large (hundreds of MB) so I don't want to use binary_oarchive to serialize them into an std::stringstream to then copy-them into their final destination. I have a Buffer class which I would like to use instead.
The problem is, binary_oarchive takes an std::ostream as parameter, and this class's stream operator is not virtual, so I can't make my Buffer class inherit from it to be used by binary_oarchive. Similarly, I haven't found a way to inherit from binary_oarchive_impl that would let me use something else than std::ostream to serialize into.
So I looked into how to create an archive from scratch, here: https://www.boost.org/doc/libs/1_79_0/libs/serialization/doc/archive_reference.html, which I'm putting back here for reference:
#include <cstddef> // std::size_t
#include <boost/archive/detail/common_oarchive.hpp>
/////////////////////////////////////////////////////////////////////////
// class complete_oarchive
class complete_oarchive :
public boost::archive::detail::common_oarchive<complete_oarchive>
{
// permit serialization system privileged access to permit
// implementation of inline templates for maximum speed.
friend class boost::archive::save_access;
// member template for saving primitive types.
// Specialize for any types/templates that require special treatment
template<class T>
void save(T & t);
public:
//////////////////////////////////////////////////////////
// public interface used by programs that use the
// serialization library
// archives are expected to support this function
void save_binary(void *address, std::size_t count);
};
But unless I misunderstood something, it looks like by defining my archive this way, I need to overload the save method for every single type I want to store, in particular STL types, which kind of defies the point of using Boost serialization altogether. If I don't define save at all, I'm getting compilation errors indicating that a save function could not be found, in particular for things like std::string and for boost-specific types like boost::archive::version_type.
So my question is: how would you make it possible, with Boost serialization, to serialize in binary format into a custom Buffer object, while retaining all the power of Boost (i.e. not having to redefine how every single STL container and boost type is serialized)?
This is something I've done pretty easily in the past with the Cereal library, unfortunately I'm stuck with Boost for this particular code base.
Don't create your own archive class. Like the commenter said, use the streambuf interface to your advantage. The upside is that things will work for any of the archive implementations, including binary archives, and perhaps more interestingly things like the EOS Portable Archive implementation.
The streambuf interface can be quite flexible. E.g. i've used it to implement hashing/equality operations:
Generate operator== using Boost Serialization?
In that answer I used Boost Iostreams with its Device concept to make implementing things simpler.
Now if your Buffer type (which you might have shown) has an interface that resembles most buffers (i.e. one or more (void*,size) pairs), you could use existing adapters present in Boost IOstreams. E.g.
Boost: Re-using/clearing text_iarchive for de-serializing data from Asio:receive()
where I show how to use Serialization with a re-usable fixed buffer. Here's the Proof Of Concept:
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>
#include <sstream>
namespace bar = boost::archive;
namespace bio = boost::iostreams;
struct Packet {
int i;
template <typename Ar> void serialize(Ar& ar, unsigned) { ar & i; }
};
namespace Reader {
template <typename T>
Packet deserialize(T const* data, size_t size) {
static_assert(boost::is_pod<T>::value , "T must be POD");
static_assert(boost::is_integral<T>::value, "T must be integral");
static_assert(sizeof(T) == sizeof(char) , "T must be byte-sized");
bio::stream<bio::array_source> stream(bio::array_source(data, size));
bar::text_iarchive ia(stream);
Packet result;
ia >> result;
return result;
}
template <typename T, size_t N>
Packet deserialize(T (&arr)[N]) {
return deserialize(arr, N);
}
template <typename T>
Packet deserialize(std::vector<T> const& v) {
return deserialize(v.data(), v.size());
}
template <typename T, size_t N>
Packet deserialize(boost::array<T, N> const& a) {
return deserialize(a.data(), a.size());
}
}
template <typename MutableBuffer>
void serialize(Packet const& data, MutableBuffer& buf)
{
bio::stream<bio::array_sink> s(buf.data(), buf.size());
bar::text_oarchive ar(s);
ar << data;
}
int main() {
boost::array<char, 1024> arr;
for (int i = 0; i < 100; ++i) {
serialize(Packet { i }, arr);
Packet roundtrip = Reader::deserialize(arr);
assert(roundtrip.i == i);
}
std::cout << "Done\n";
}

Can static polymorphism (templates) be used despite type erasure?

Having returned relatively recently to C++ after decades of Java, I am currently struggling with a template-based approach to data conversion for instances where type erasure has been applied. Please bear with me, my nomenclature may still be off for C++-natives.
This is what I am trying to achieve:
Implement dynamic variables which are able to hold essentially any value type
Access the content of those variables using various other representations (string, ints, binary, ...)
Be able to hold variable instances in containers, independent of their value type
Convert between variable value and representation using conversion functions
Be able to introduce new representations just by providing new conversion functions
Constraints: use only C++-11 features if possible, no use of libraries like boost::any etc.
A rough sketch of this might look like this:
#include <iostream>
#include <vector>
void convert(const std::string &f, std::string &t) { t = f; }
void convert(const int &f, std::string &t) { t = std::to_string(f); }
void convert(const std::string &f, int &t) { t = std::stoi(f); }
void convert(const int &f, int &t) { t = f; }
struct Variable {
virtual void get(int &i) = 0;
virtual void get(std::string &s) = 0;
};
template <typename T> struct VariableImpl : Variable {
T value;
VariableImpl(const T &v) : value{v} {};
void get(int &i) { convert(value, i); };
void get(std::string &s) { convert(value, s); };
};
int main() {
VariableImpl<int> v1{42};
VariableImpl<std::string> v2{"1234"};
std::vector<Variable *> vars{&v1, &v2};
for (auto &v : vars) {
int i;
v->get(i);
std::string s;
v->get(s);
std::cout << "int representation: " << i <<
", string representation: " << s << std::endl;
}
return 0;
}
The code does what it is supposed to do, but obvoiusly I would like to get rid of Variable::get(int/std::string/...) and instead template them, because otherwise every new representation requires a definition and an implementation with the latter being exactly the same as all the others.
I've played with various approaches so far, like virtual templated, methods, applying the CRDT with intermediate type, various forms of wrappers, yet in all of them I get bitten by the erased value type of VariableImpl. On one hand, I think there might not be a solution, because after type erasure, the compiler cannot possibly know what templated getters and converter calls it must generate. On the other hand I think i might be missing something really essential here and there should be a solution despite the constraints mentioned above.
This is a classical double dispatch problem. The usual solution to this problem is to have some kind of dispatcher class with multiple implementations of the function you want to dispatch (get in your case). This is called the visitor pattern. The well-known drawback of it is the dependency cycle it creates (each class in the hierarchy depends on all other classes in the hierarchy). Thus there's a need to revisit it each time a new type is added. No amount of template wizardry eliminates it.
You don't have a specialised Visitor class, your Variable serves as a Visitor of itself, but this is a minor detail.
Since you don't like this solution, there is another one. It uses a registry of functions populated at run time and keyed on type identification of their arguments. This is sometimes called "Acyclic Visitor".
Here's a half-baked C++11-friendly implementation for your case.
#include <map>
#include <vector>
#include <typeinfo>
#include <typeindex>
#include <utility>
#include <functional>
#include <string>
#include <stdexcept>
struct Variable
{
virtual void convertValue(Variable& to) const = 0;
virtual ~Variable() {};
virtual std::type_index getTypeIdx() const = 0;
template <typename K> K get() const;
static std::map<std::pair<std::type_index, std::type_index>,
std::function<void(const Variable&, Variable&)>>
conversionMap;
template <typename T, typename K>
static void registerConversion(K (*fn)(const T&));
};
template <typename T>
struct VariableImpl : Variable
{
T value;
VariableImpl(const T &v) : value{v} {};
VariableImpl() : value{} {}; // this is needed for a declaration of
// `VariableImpl<K> below
// It can be avoided but it is
// a story for another day
void convertValue(Variable& to) const override
{
auto typeIdxFrom = getTypeIdx();
auto typeIdxTo = to.getTypeIdx();
if (typeIdxFrom == typeIdxTo) // no conversion needed
{
dynamic_cast<VariableImpl<T>&>(to).value = value;
}
else
{
auto fcnIter = conversionMap.find({getTypeIdx(), to.getTypeIdx()});
if (fcnIter != conversionMap.end())
{
fcnIter->second(*this, to);
}
else
throw std::logic_error("no conversion");
}
}
std::type_index getTypeIdx() const override
{
return std::type_index(typeid(T));
}
};
template <typename K> K Variable::get() const
{
VariableImpl<K> vk;
convertValue(vk);
return vk.value;
}
template <typename T, typename K>
void Variable::registerConversion(K (*fn)(const T&))
{
// add a mutex if you ever spread this over multiple threads
conversionMap[{std::type_index(typeid(T)), std::type_index(typeid(K))}] =
[fn](const Variable& from, Variable& to) {
dynamic_cast<VariableImpl<K>&>(to).value =
fn(dynamic_cast<const VariableImpl<T>&>(from).value);
};
}
Now of course you need to call registerConversion e.g. at the beginning of main and pass it each conversion function.
Variable::registerConversion(int_to_string);
Variable::registerConversion(string_to_int);
This is not ideal, but hardly anything is ever ideal.
Having said all that, I would recommend you revisit your design. Do you really need all these conversions? Why not pick one representation and stick with it?
Implement dynamic variables which are able to hold essentially any value type
Be able to hold variable instances in containers, independent of their value type
These two requirements are quite challenging on its own. The class templates don't really encourage inheritance, and you already did the right thing to hold what you asked for: introduced a common base class for the class template, which you can later refer to in order to store pointers of the said type in a collection.
Access the content of those variables using various other representations (string, ints, binary, ...)
Be able to introduce new representations just by providing new conversion functions
This is where it breaks. Function templates assume common implementation for different types, while inheritance assumes different implementation for the same types.
You goal is to introduce different implementation for different types, and in order to make your requirements viable you have to switch to one of those two options instead (or put up with a number of functions for each case which you have already introduced yourself)
Edit:
One of the strategies you may employ to enforce inheritance approach is generalisation of the arguments to the extent where they can be used interchangeably by the abstract interface. E.g. you may wrap the converting arguments inside of a union like this:
struct Variable {
struct converter_type {
enum { INT, STRING } type;
union {
int* m_int;
std::string* m_string;
};
};
virtual void get(converter_type& var) = 0;
virtual ~Variable() = default;
};
And then take whatever part of it inside of the implementation:
void get(converter_type& var) override {
switch (var.type) {
case converter_type::INT:
convert(value, var.m_int);
break;
case converter_type::STRING:
convert(value, var.m_string);
break;
}
}
To be honest I don't think this is a less verbose approach compared to just having a number of functions for each type combination, but i think you got the idea that you can just wrap your arguments somehow to cement the abstract class interface.
Implement std::any. It is similar to boost::any.
Create a conversion dispatcher based off typeids. Store your any alongside the conversion dispatcher.
"new conversion functions" have to be passed to the dispatcher.
When asked to convert to a type, pass that typeid to the dispatcher.
So we start with these 3 types:
using any = std::any; // implement this
using converter = std::function<any(any const&)>;
using convert_table = std::map<std::type_index, converter>;
using convert_lookup = convert_table(*)();
template<class T>
convert_table& lookup_convert_table() {
static convert_table t;
return t;
}
struct converter_any: any {
template<class T,
typename std::enable_if<
!std::is_same<typename std::decay<T>::type, converter_any>::value, bool
>::type = true
>
converter_any( T&& t ):
any(std::forward<T>(t)),
table(&lookup_convert_table<typename std::decay<T>::type>())
{}
converter_any(converter_any const&)=default;
converter_any(converter_any &&)=default;
converter_any& operator=(converter_any const&)=default;
converter_any& operator=(converter_any&&)=default;
~converter_any()=default;
converter_any()=default;
convert_table const* table = nullptr;
template<class U>
U convert_to() const {
if (!table)
throw 1; // make a better exception than int
auto it = table->find(typeid(U));
if (it == table->end())
throw 2; // make a better exception than int
any const& self = *this;
return any_cast<U>((it->second)(self));
}
};
template<class Dest, class Src>
bool add_converter_to_table( Dest(*f)(Src const&) ) {
lookup_convert_table<Src>()[typeid(Dest)] = [f](any const& s)->any {
Src src = std::any_cast<Src>(s);
auto r = f(src);
return r;
};
return true;
}
now your code looks like:
const bool bStringRegistered =
add_converter_to_table(+[](std::string const& f)->std::string{ return f; })
&& add_converter_to_table(+[](std::string const& f)->int{ return std::stoi(f); });
const bool bIntRegistered =
add_converter_to_table(+[](int const& i)->int{ return i; })
&& add_converter_to_table(+[](int const& i)->std::string{ return std::to_string(i); });
int main() {
converter_any v1{42};
converter_any v2{std::string("1234")};
std::vector<converter_any> vars{v1, v2}; // copies!
for (auto &v : vars) {
int i = v.convert_to<int>();
std::string s = v.convert_to<std::string>();
std::cout << "int representation: " << i <<
", string representation: " << s << std::endl;
}
}
live example.
...
Ok, what did I do?
I used any to be a smart void* that can store anything. Rewriting this is a bad idea, use someone else's implementation.
Then, I augmented it with a manually written virtual function table. Which table I add is determined by the constructor of my converter_any; here, I know the type stored, so I can store the right table.
Typically when using this technique, I'd know what functions are in there. For your implementation we do not; so the table is a map from the type id of the destination, to a conversion function.
The conversion function takes anys and returns anys -- again, don't repeat this work. And now it has a fixed signature.
To add support for a type, you independently register conversion functions. Here, my conversion function registration helper deduces the from type (to determine which table to register it in) and the destination type (to determine which entry in the table), and then automatically writes the any boxing/unboxing code for you.
...
At a higher level, what I'm doing is writing my own type erasure and object model. C++ has enough power that you can write your own object models, and when you want features that the default object model doesn't solve, well, roll a new object model.
Second, I'm using value types. A Java programmer isn't used to value types having polymorphic behavior, but much of C++ works much better if you write your code using value types.
So my converter_any is a polymorphic value type. You can store copies of them in vectors etc, and it just works.

C++ Push Multiple Types onto Vector

Note: I know similar questions to this have been asked on SO before, but I did not find them helpful or very clear.
Second note: For the scope of this project/assignment, I'm trying to avoid third party libraries, such as Boost.
I am trying to see if there is a way I can have a single vector hold multiple types, in each of its indices. For example, say I have the following code sample:
vector<something magical to hold various types> vec;
int x = 3;
string hi = "Hello World";
MyStruct s = {3, "Hi", 4.01};
vec.push_back(x);
vec.push_back(hi);
vec.push_back(s);
I've heard vector<void*> could work, but then it gets tricky with memory allocation and then there is always the possibility that certain portions in nearby memory could be unintentionally overridden if a value inserted into a certain index is larger than expected.
In my actual application, I know what possible types may be inserted into a vector, but these types do not all derive from the same super class, and there is no guarantee that all of these types will be pushed onto the vector or in what order.
Is there a way that I can safely accomplish the objective I demonstrated in my code sample?
Thank you for your time.
The objects hold by the std::vector<T> need to be of a homogenous type. If you need to put objects of different type into one vector you need somehow erase their type and make them all look similar. You could use the moral equivalent of boost::any or boost::variant<...>. The idea of boost::any is to encapsulate a type hierarchy, storing a pointer to the base but pointing to a templatized derived. A very rough and incomplete outline looks something like this:
#include <algorithm>
#include <iostream>
class any
{
private:
struct base {
virtual ~base() {}
virtual base* clone() const = 0;
};
template <typename T>
struct data: base {
data(T const& value): value_(value) {}
base* clone() const { return new data<T>(*this); }
T value_;
};
base* ptr_;
public:
template <typename T> any(T const& value): ptr_(new data<T>(value)) {}
any(any const& other): ptr_(other.ptr_->clone()) {}
any& operator= (any const& other) {
any(other).swap(*this);
return *this;
}
~any() { delete this->ptr_; }
void swap(any& other) { std::swap(this->ptr_, other.ptr_); }
template <typename T>
T& get() {
return dynamic_cast<data<T>&>(*this->ptr_).value_;
}
};
int main()
{
any a0(17);
any a1(3.14);
try { a0.get<double>(); } catch (...) {}
a0 = a1;
std::cout << a0.get<double>() << "\n";
}
As suggested you can use various forms of unions, variants, etc. Depending on what you want to do with your stored objects, external polymorphism could do exactly what you want, if you can define all necessary operations in a base class interface.
Here's an example if all we want to do is print the objects to the console:
#include <iostream>
#include <string>
#include <vector>
#include <memory>
class any_type
{
public:
virtual ~any_type() {}
virtual void print() = 0;
};
template <class T>
class concrete_type : public any_type
{
public:
concrete_type(const T& value) : value_(value)
{}
virtual void print()
{
std::cout << value_ << '\n';
}
private:
T value_;
};
int main()
{
std::vector<std::unique_ptr<any_type>> v(2);
v[0].reset(new concrete_type<int>(99));
v[1].reset(new concrete_type<std::string>("Bottles of Beer"));
for(size_t x = 0; x < 2; ++x)
{
v[x]->print();
}
return 0;
}
In order to do that, you'll definitely need a wrapper class to somehow conceal the type information of your objects from the vector.
It's probably also good to have this class throw an exception when you try to get Type-A back when you have previously stored a Type-B into it.
Here is part of the Holder class from one of my projects. You can probably start from here.
Note: due to the use of unrestricted unions, this only works in C++11. More information about this can be found here: What are Unrestricted Unions proposed in C++11?
class Holder {
public:
enum Type {
BOOL,
INT,
STRING,
// Other types you want to store into vector.
};
template<typename T>
Holder (Type type, T val);
~Holder () {
// You want to properly destroy
// union members below that have non-trivial constructors
}
operator bool () const {
if (type_ != BOOL) {
throw SomeException();
}
return impl_.bool_;
}
// Do the same for other operators
// Or maybe use templates?
private:
union Impl {
bool bool_;
int int_;
string string_;
Impl() { new(&string_) string; }
} impl_;
Type type_;
// Other stuff.
};

boost.serialization - free version and base class implementation

I have a "generator" class that basically constructs its subclass. To use this thing I simply subclass it and pass it the correct parameters to build the object I want built. I want to serialize these things and there's no good reason to do it for each subclass since all the data is in the base. Here's what I've got as example:
#include <boost/serialization/serialization.hpp>
template < typename T >
struct test_base
{
// works...
//template < typename Archive >
//void serialize(Archive &, unsigned int const)
// {
//}
};
template < typename T >
void f(test_base<T> const&) {}
struct test_derived : test_base<int>
{
};
namespace boost { namespace serialization {
template < typename Archive, typename T >
void serialize(Archive &, test_base<T> &, unsigned int const)
{
}
}}
#include <boost/archive/binary_oarchive.hpp>
#include <sstream>
int main()
{
int x = 5;
test_derived d;
//boost::serialization::serialize(x, d, 54); // <- works.
std::ostringstream str;
boost::archive::binary_oarchive out(str);
out & d; // no worky.
}
I want the free version to work if possible. Is it?
Version above pukes up error about serialize not being a member of test_derived.
Clarification why the problem happens:
boost::serialization has to ways of implementing the serialize function. As class method or (in your case) the non-intrusive way of defining a function in the boost::serialization namespace.
So the compiler has to somehow decide which implementation to choose. For that reason boost has a 'default' implementation of the boost::serialization::serialize template function.
Signature:
template<class Archive, class T>
inline void serialize(Archive & ar, T & t, const BOOST_PFTO unsigned int file_version)
Within that function there is a call to T::serialize(...). So when you don't want the intusive version you have to override the boost::serialization::serialize function with something more explicit than the default function-template.
Now the problem: In your case the compiler has to decide if it
a) chooses the version where a parameter has to be casted implicit (test_derived& to test_base&)
b) use the generic function without casting (T is test_derived&)
You want the compiler to use variant a) but the compiler prefers b)
Solution:
I don't know a really good solution. I think i would go with a macro which generates implementations of serialize(...) with the explicit type.
If that isn't a possible solution for you, you could also tell the compiler more explicit what to call:
out & *((test_base<int>*)&d);
and wrap it in some helper function (because no one wants to look at such code all the day)
I hope that is a clear description and helps
In case my explanation was not clear, here is an example:
#include <iostream>
class Base
{
public:
virtual ~Base()
{
}
};
class Derived : public Base
{
public:
virtual ~Derived()
{
}
};
void foo(Base& bar)
{
std::cout << "special" << std::endl;
}
template<typename T>
void foo(T& bar)
{
std::cout << "generic" << std::endl;
}
int main()
{
Derived derived;
foo(derived); // => call to generic implementation
foo(*((Base*) &bla)); // => call to special
return 0;
}

C++ template specialization question

I'm trying to implement a generic toString() function that would work on all types. All our internal classes derive from Abstract which includes a signature for toString(). In other words, all our internal classes have in some form, a toString method.
The problem is, the primitive types (int, char, double..) don't have a native toString function. But we do have a utility function that calls the lexical_cast to give back the string value of the primitive. We don't want a whole bunch of if statements depending So I'm trying to create a templated utility class that would do the job.
My first hack at this is the below:
template<class T>
class ObjectToString {
public:
string objectToString(T value) {
iil::stringUtils::StringSp ret(stringUtils::valueToString<T>(value));
return ret;
}
};
template<>
class ObjectToString <Abstract<T>*> {
public:
iil::stringUtils::StringSp objectToString(Abstract<T>* value) {
return iil::stringUtils::StringSp(new std::string("AAAA"));
}
};
The problem now is, since Abstract is a templated class, it needs the template value T. I have no idea how to set that. Could anyone advise?
How about simply providing a specialization for lexical_cast?
template<> string lexical_cast(Abstract* obj)
{
return obj->toString();
}
Isn't your problem much simpler? On all Abstract objects you know what to do, so all you need is to provide overloaded functions for built-in types:
string getAsString(Abstract *obj)
{
return obj->toString();
}
string getAsString(int x)
{
return intToStr(x);
}
string getAsString(double x)
{
return doubleToStr(x);
}
etc, where you implement intToStr() and doubleToStr() as appropriate.
This has been dealt with at length by Matthew Wilson in the form of shims, as described in this Dr Dobb's article, and the books Imperfect C++ and Extended STL. They underlie the technology that allow the FastFormat and Pantheios libraries to deal with argument types generically.
You just don't think in C++ way. C++ already has "toString" that is called operator<< to std::ostream. You need to implement it for your classes.
And if you want to support inheritence, do this:
#include <iostream>
#include <boost/lexical_cast.hpp>
#include <string>
class streamable {
public:
virtual void stream(std::ostream &) const = 0;
};
std::ostream &operator<<(std::ostream &out,streamable const &obj)
{
obj.stream(out);
return out;
}
// Now anything derived from streamable can be written to std::ostream
// For example:
class bar : public streamable {
int x;
int y;
public:
bar(int a,int b) : x(a),y(b){}
virtual void stream(std::ostream &out) const { out<<x<<":"<<y; }
};
int main()
{
bar b(1,3);
std::cout<< b << std::endl;
// and converted to string
std::string str=boost::lexical_cast<std::string>(b);
std::cout<< str <<std::endl;
}
This is C++ way, and as you can see you have boost::lexical_cast for free.
EDIT for your case:
template<typename T>
class Abstract {
public:
virtual void stream(std::ostream &) const = 0;
};
template<typename T>
std::ostream &operator<<(std::ostream &out,Abstract<T> const &obj)
{
obj.stream(out);
return out;
}
Now if you don't like boost::lexical_cast, implement string_cast as simple as
template<typename T>
std::string string_cast(T const &obj)
{
std::ostringstram ss;
ss<<obj;
return ss.str();
}