is_container特质在std :: set SFINAE问题上失败 [英] is_container trait fails on std::set SFINAE issue
问题描述
我试图为std容器编写一个流运算符,主要是为了调试。
I am trying to write a stream operator for std containers, mainly for the purpose of debugging.
我有以下代码:
#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.
谢谢。
编辑:在
g ++(GCC)上进行了测试4.6.2 2012012
clang版本3.0
tested on g++ (GCC) 4.6.2 2012012 clang version 3.0
EDIT2:我使用decltype可以使其工作,但是这是次优的,因为现在我不能断言它是否达到了我的期望(返回迭代器)。
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.
我不完全知道该集最初返回的是什么,也许有人是否有调试TMP的方法会很好。
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.
推荐答案
由于 std :: set< T>
仅具有一组不可变的迭代器,因此只有一个版本的 begin()
和 end()
被声明为 const
。也就是说, std :: set< T>
的定义看起来像这样(假设它是在命名空间 std
之前):
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;
...
};
其他容器都具有 const
和 begin()
和 end()$ c $的非
const
版本c>匹配您要求的签名。 std :: set
没有这个。我不确定这是最简单的解决方法。
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.
也就是说, sizeof(char)
允许为 sizeof(long)
。确保是
和 no
类型具有不同大小的最简单方法是使用对不同大小的数组的引用相同的类型,例如:
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) };
这篇关于is_container特质在std :: set SFINAE问题上失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!