2

我正在尝试为 std 容器编写流运算符,主要是为了调试。

我有以下代码:

#include <type_traits>
#include <iostream>
#include <ostream>
#include <iterator>
#include <algorithm>
#include <functional>

#include <vector>
#include <set>
#include <deque>


template<typename Container>
struct is_container
{
    typedef char no;
    typedef long yes;


    template<typename A, A, A>
    struct is_of_type;

    template<typename T>
            static yes& is_cont(
                            is_of_type
                            <
                                    typename T::iterator(T::*)(), 
                                    &T::begin,
                                    &T::end
                            >*);


    template<typename T>
    static no& is_cont(...);        //any other

    template<typename C, bool B>
    struct is_class_is_container
    {
            const static bool value=sizeof( is_cont<C>(nullptr) )==sizeof(yes);
    };

    template<typename C>
    struct is_class_is_container<C, false>
    {
            const static bool value=false;
    };

    const static bool value = is_class_is_container
            <
                    Container, 
                    std::is_class<Container>::value 
            >::value;
};

template<typename T>
    typename std::enable_if
    < is_container<T>::value, std::ostream >::type& 
    operator<<(std::ostream& os, const T& a)
{
    os << '[';
    std::copy(a.begin(), a.end(), std::ostream_iterator<typename T::value_type>(os, ", "));
    os << ']';
    return os;
}

我知道这远非完美(赞赏有建设性的评论),但我遇到的问题是它适用于向量、双端队列和列表但无法在集合上匹配,我不知道为什么,因为集合仍然具有迭代器接口开始和结束。

谢谢。

编辑:在 g++ (GCC) 4.6.2 2012012 clang 版本 3.0 上测试

EDIT2:我使用 decltype 得到了它的工作,但是这是次优的,因为现在我不能断言它做了我期望的(返回一个迭代器)。

我不完全知道该集合首先返回的是什么,也许如果有人有一种调试 TMP 的方法会很好。

4

2 回答 2

4

由于std::set<T>只有一组不可变迭代器,因此只有一个版本的begin()andend()被声明为const. 也就是说, 的定义std::set<T>看起来像这样(假设它之前在命名空间中声明std过):

template <typename T>
class std::set
{
public:
    class            iterator;
    typedef iterator const_iterator;
    ...
    const_iterator begin() const;
    const_iterator end() const;
    ...
};

其他容器有一个const和一个非const版本begin()end()匹配您要求的签名。std::set没有这个。我不确定最简单的解决方法是什么。

也就是说,sizeof(char)是允许的sizeof(long)。保证yesno类型具有不同大小的最简单方法是使用对同一类型的不同大小数组的引用,例如:

typedef char (&yes)[1];
typedef char (&no)[2];
...
enum { value = sizeof(some_expression) == sizeof(yes) };
于 2012-02-11T18:05:18.937 回答
2

它适用于vector但不适用于,因为set后者返回/函数。改变:const_iteratorbeginend

typename T::iterator(T::*)(), 

到:

typename T::const_iterator(T::*)() const, 
于 2012-02-11T18:15:01.033 回答