如何强制运算符&gt;&gt;(C <t>)重载以匹配容器?

时间:2015-06-21 01:49:08

标签: c++ templates operator-overloading containers extraction-operator

我希望任何&#34; base&#34;都有operator>>()次重载类型和任何容器类型。这就是我到目前为止所做的:

typedef uintmax_t my_t;
template <typename T>
std::istringstream &operator>>(std::istringstream &iss, T &v)
{
    static my_t um = 6009;
    v = um++;
    return iss;
}

template <template <class> class C, typename T>
std::istringstream &operator>>(std::istringstream &iss, C<T> &c)
{
    for (typename C<T>::iterator it = c.begin(); it != c.end(); ++it)
        iss >> *it;
    return iss;
}

int main()
{
    std::vector<uint32_t> vi(3);
    std::istringstream iss;
    iss >> vi;
    for (std::vector<uint32_t>::iterator it = vi.begin(); it != vi.end(); ++it)
        std::cout << *it << std::endl;
}

这与GCC一样编译并运行,但在VS2015上甚至没有编译。后者匹配>>语句中的iss >> vi;运算符与第一个基类型重载,这会触发其他编译错误。如何为非容器类型编写operator>>()模板,为GCC和VS2015编译容器类型的模板(无需专门针对每种容器类型)?

1 个答案:

答案 0 :(得分:5)

您编写的operator>>重载是针对具有单个模板参数(C)的模板模板类(T)。但是,std::vector声明为:

template<
    class T,
    class Allocator = std::allocator<T>
> class vector;

第二个模板参数可能是默认的,但它仍然存在。因此,std::vector<uint32_t>无法与C<T>匹配 - 因此唯一可行的重载是您编写的通用函数模板,由于您无法将std::uintmax_t分配给{ {1}}。

为了让你的函数接受vector,你需要匹配模板模板声明 - 这意味着,采取第二种类型参数:

vector

但这是一个非常令人不满意的解决方案。真的,我们希望匹配任何容器,我们可以使用SFINAE。由于这是C ++ 03,最简单的方法是编写一个类型特征,判断某个类型是否有一个名为template <template <class, class> class C, typename T1, typename T2> std::istringstream &operator>>(std::istringstream &iss, C<T1,T2> &c) { for (typename C<T1,T2>::iterator it = c.begin(); it != c.end(); ++it) iss >> *it; return iss; } 的typedef:

iterator

添加我们方便的template <typename T> struct is_container { typedef char yes; struct no { char _[2]; }; template <typename U> static yes test( typename U::iterator* ); template <typename U> static no test(...); static const bool value = (sizeof(test<T>(0)) == sizeof(yes)); };

enable_if

并坚持返回类型:

template <bool, typename >
struct enable_if { };

template <typename T>
struct enable_if<true, T> { 
    typedef T type;
};

你必须对另一个重载执行相反的操作(template <typename C> typename enable_if< is_container<C>::value, std::istringstream& >::type operator>>(std::istringstream &iss, C& c) { for (typename C::iterator it = c.begin(); it != c.end(); ++it) iss >> *it; return iss; } ),这样它们就不会模糊不清。