c++ - 如何强制 operator>>(C<T>) 重载以匹配容器?

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

我希望为任何“基本”类型和任何容器类型重载 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 编译的容器类型模板(无需专门针对每种容器类型)?

最佳答案

operator>>您编写的重载适用于具有单个模板参数( C )的模板模板类( T )。然而, std::vector 声明为:

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

第二个模板参数可能是默认的,但它仍然存在。因此,std::vector<uint32_t>无法匹配 C<T> - 所以唯一可行的重载是你写的通用函数模板,它不会编译,因为你不能分配 std::uintmax_tvector .

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

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

虽然这是一个非常不令人满意的解决方案。真的,我们想要匹配任何容器,我们可以使用 SFINAE 来做到这一点。因为这是 C++03,最简单的事情是写一个类型特征来判断某个类型是否有一个名为 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;
}

您必须对另一个重载执行相反的操作 ( !is_container<T>::value ),这样它们才不会模棱两可。

关于c++ - 如何强制 operator>>(C<T>) 重载以匹配容器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30960543/

相关文章:

c++ - template 模板参数场景

c++ - 与 boost::mpl 占位符评估不一致的行为

c++ - operator << argument-dependent lookup 不在全局命名空间中查找

javascript - 覆盖 Javascript 中的等价比较

c++ 使用 "*"运算符没有运算符匹配这些操作数

php - 实时地理数据流分析

c++ - 根据SSE特性调用不同的函数实现

c++ - 如何找到模板函数接受的参数数量?

wpf - 在 WPF 中的不同控件上显示验证错误模板

c++ - 类型名和标量常量的可变参数模板