On Tue, Jun 2, 2009 at 2:31 AM, Ryan McConnehey <mccorywork@gmail.com> wrote:
Scott McMurray wrote:
They're at least simple, but it's still a violation of DRY,
so I'm not a big fan.
 
If a non-expanding interface is needed (non-template so that every type isn't accepted) does it really violate DRY?


What are the types really, anyways?
I've create true_typedef of the basic type like uint16, uint32, int16, etc.  I've written my own serialization interface (I know boost already has one) and I'm restricting the interface to only allow certain types.  I'm trying to centralize the were the real work happens so if new types are needed then added them won't be difficult.

Is there any reason you have to have different names for the map?  Use template specialization to achieve the same thing as name resolution for you but still allowing you to access the maps through a consistent naming scheme.

//The default specialization will cause compilation to fail unless DECL_SERIALIZATION_SUPPORT(T) has been called for a type
#define BEGIN_SERIALIZATION_DECLS() \
    namespace serialization { \
        template<typename T> struct kv_map { }; \

#define DECL_SERIALIZATION_SUPPORT(T) \
        template<>  \
        struct kv_map<T> \
        { \
            typedef std::map<std::string, T> map_type; \
            map_type map; \
        }; \
        kv_map<T>::map_type map;

#define END_SERIALIZATION_DECLS() }

template<typename T> void store_kv(const std::string& key, const T& value)
{
    serialization::kv_map<T>::map[key] = value;
}

template<typename T> T& retrieve_kv(const std::string& key)
{
    return serialization::kv_map<T>::map[key];
}

now you don't even need the put function at all anymore, and you can invoke it like this:

BEGIN_SERIALIZATION_DECLS()
DECL_SERIALIZAITON_SUPPORT(boost::uint16_t)
DECL_SERIALIZATION_SUPPORT(boost::uint32_t)
END_SERIALIZATION_DECLS()

boost::uint16_t test1 = 7;
boost::uint32_t test2 = 8;

store_kv("test1", test1);
store_kv("test2", test2);

test1 = retrieve_kv<boost::uint16_t>("test1");
test2 = retrieve_kv<boost::uint32_t>("test2");


If you need to provide different storage / retrieval logic for different types then just specialize the store_kv and retrieve_kv functions.  When you want to support a new type you only add 1 line of code, a DECL_SERIALIZATION_SUPPORT macro.

I used a very similar method to this to provide compile-time lookup of the names of the different fields in an enum and it works well.