1

I am writing a sort of serialization class. It must provide functions for containers. Current implementation is:

template <typename InsertIter>
bool readContainer(InsertIter result)
{
    typedef typename InsertIter::container_type::value_type tVal;
    UInt32 size = 0;

    if (!read(size))
        return false;

    for (UInt32 i = 0; i < size; ++i)
    {
        tVal val;
        if (!read(val))
            return false;
        *result++ = val;
    }
    return true;
}

template <typename InsertIter>
bool readMap(InsertIter result)
{
    typedef typename InsertIter::container_type::key_type tKey;
    typedef typename InsertIter::container_type::mapped_type tVal;
    UInt32 size = 0;

    if (!read(size))
        return false;

    for (UInt32 i = 0; i < size; ++i)
    {
        std::pair<tKey, tVal> pair;
        if (!read(pair))
            return false;
        *result++ = pair;
    }
    return true;
}

As you can see, I must to create different implementations for map-like types (std::map) and other containers, because std::map::value_type is std::pair(const K, V) and not std::pair(K, V).

So, I want to create method read(InsertIter) which will automatically select appropriate readContainer(InsertIter) or readMap(InsertIter). Is this possible?

pashkoff
  • 147
  • 3
  • 11
  • 2
    Have a look here http://stackoverflow.com/questions/9530928/checking-a-member-exists-possibly-in-a-base-class-c11-version – Johan Lundberg Jul 15 '12 at 13:45
  • Specifically look here http://stackoverflow.com/a/9531274/1149664. This shows how to enable/disable a method. Possible Duplicate? – Johan Lundberg Jul 15 '12 at 13:52
  • 1
    Look at the code [here](http://nicola-bonelli-repo.googlecode.com/svn-history/r728/trunk/codes.cpp0x/type_traits.hpp). There are `has_value_type` and `has_key_type` templates that you can use as is to select the correct implementation with `std::enable_if`. – n. m. could be an AI Jul 15 '12 at 14:20

2 Answers2

0

I have an example that does something very similar, and it should be very simple for you to convert to something that you need :

#include <iostream>

template< typename T >
struct A;

template<>
struct A< int >
{
    void foo() const
    {
        std::cout<<"A(int)::foo()"<<std::endl;
    }
};
template<>
struct A< float >
{
    void foo() const
    {
        std::cout<<"A(float)::foo()"<<std::endl;
    }
};

template< typename T >
void call( const A<T> &a)
{
    a.foo();
}

struct B
{
    template<typename T>
    void bar(const A<T> &a)
    {
        call(a);
    }
};

int main()
{
    A<int> a1;
    A<float> a2;

    B b;
    b.bar(a1);
    b.bar(a2);
}

You need to give proper names, and replace int and float in the above example with appropriate container types, and implement needed functionality.

BЈовић
  • 62,405
  • 41
  • 173
  • 273
0

I have successfully solved my problem.

Thanks to Johan Lundberg and especially to n.m. - I was not familiar with SFINAE idiom and your links and samples helped me a lot.

I was not able to use C++11 features (project specifics), but they are not needed.

Current code looks like this:

struct SFINAE
{
    typedef char __one;
    typedef struct { char __arr[2]; } __two;
};

template <typename T> 
class has_mapped_type : public SFINAE
{
    template <typename C> static __one test(typename C::mapped_type *);
    template <typename C> static __two test(...);
public:
    enum { value = (sizeof(test<T>(0)) == sizeof(__one)) };
};

class Serializer
{
    template <typename InsertIter>
    bool read(InsertIter result) const
    {
        return readContainerSelector< InsertIter, 
            has_mapped_type<typename InsertIter::container_type>::value
            > ::read(result, *this);
    }

    template <typename InsertIter, bool isMapType>
    struct readContainerSelector;

    template <typename InsertIter>
    struct readContainerSelector<InsertIter, true>
    {
        static bool read(InsertIter result, Serializer const& ser)
        {
            return ser.readMap(result);
        }
    };

    template <typename InsertIter>
    struct readContainerSelector<InsertIter, false>
    {
        static bool read(InsertIter result, Serializer const& ser)
        {
            return ser.readContainer(result);
        }
    };

    // methods from my topic post
    template <typename InsertIter> bool readContainer(InsertIter result);
    template <typename InsertIter> bool readMap(InsertIter result)

};
pashkoff
  • 147
  • 3
  • 11