根据成员类型可用性选择C ++模板专业化

时间:2012-07-15 13:35:27

标签: c++ templates

我正在编写一种序列化类。它必须为容器提供功能。目前的实施是:

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;
}

如您所见,我必须为类似地图的类型(std::map)和其他容器创建不同的实现,因为std::map::value_typestd::pair(const K, V)而不是std::pair(K, V)

所以,我想创建方法read(InsertIter),它会自动选择合适的readContainer(InsertIter)readMap(InsertIter)。这可能吗?

2 个答案:

答案 0 :(得分:0)

我有一个非常相似的例子,你可以很简单地转换成你需要的东西:

#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);
}

您需要提供正确的名称,并将上述示例中的intfloat替换为适当的容器类型,并实现所需的功能。

答案 1 :(得分:0)

我已成功解决了我的问题。

感谢Johan Lundberg,尤其感谢上午。 - 我不熟悉SFINAE成语,你的链接和样本给了我很多帮助。

我无法使用C ++ 11功能(项目细节),但不需要它们。

当前代码如下所示:

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)

};