is_container 特征在 std::set SFINAE 问题上失败

发布于 2025-01-04 09:02:44 字数 2025 浏览 0 评论 0原文

我正在尝试为 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++(海湾合作委员会)4.6.2 2012012 clang 版本 3.0

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

我一开始并不完全知道返回的集合是什么,也许如果有人有一种调试 TMP 的方法那就太好了。

I am trying to write a stream operator for std containers, mainly for the purpose of debugging.

I have the following code:

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

I am aware this is far from perfect (constructive comments appreciated) but the problem I am having is that it works great for vector, deque and list but fails to match on sets, I don't know why because sets still have the iterator interfaces begin and end.

Thanks.

EDIT: tested on
g++ (GCC) 4.6.2 2012012
clang version 3.0

EDIT2: I got it sort of working using decltype however that is sub optimal because now I can't assert that it does what I expect (return an iterator) to.

I don't exactly know what the set was return in the first place, maybe if someone has a way of debugging TMP that would be good.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

錯遇了你 2025-01-11 09:02:44

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

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

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

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

typedef char (&yes)[1];
typedef char (&no)[2];
...
enum { value = sizeof(some_expression) == sizeof(yes) };

Since std::set<T> only has one set of immutable iterators, there is only one version of begin() and end() which is declared to be const. That is, the definition of std::set<T> looks something like this (assuming it was declared in namespace std before):

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

The other containers have both a const and a non-const version of begin() and end() matching the signature you ask for. std::set doesn't have this. I'm not sure what the easiest work-around for this would be though.

That said, sizeof(char) is allowed to be sizeof(long). The easiest way to guarantee that the yes and no types have different size is to use references to arrays of different sizes for the same type, e.g.:

typedef char (&yes)[1];
typedef char (&no)[2];
...
enum { value = sizeof(some_expression) == sizeof(yes) };
左岸枫 2025-01-11 09:02:44

它适用于vector,但不适用于set,因为后者为begin/endconst_iterator代码>函数。更改:

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

至:

typename T::const_iterator(T::*)() const, 

It works for vector but not for set because the latter returns const_iterator for begin/end functions. Change:

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

to:

typename T::const_iterator(T::*)() const, 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文