is_container 特征在 std::set SFINAE 问题上失败
我正在尝试为 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
由于的定义看起来像这样(假设它之前在命名空间
std::set
只有一组不可变迭代器,因此begin()
和end()
只有一个版本它被声明为 const。也就是说,std::setstd
中声明过):其他容器都有一个
>const
以及与您要求的签名匹配的begin()
和end()
的非const
版本。std::set
没有这个。我不确定最简单的解决方法是什么。也就是说,
sizeof(char)
允许为sizeof(long)
。保证 yes 和 no 类型具有不同大小的最简单方法是使用对同一类型的不同大小数组的引用,例如:Since
std::set<T>
only has one set of immutable iterators, there is only one version ofbegin()
andend()
which is declared to beconst
. That is, the definition ofstd::set<T>
looks something like this (assuming it was declared in namespacestd
before):The other containers have both a
const
and a non-const
version ofbegin()
andend()
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 besizeof(long)
. The easiest way to guarantee that theyes
andno
types have different size is to use references to arrays of different sizes for the same type, e.g.:它适用于
vector
,但不适用于set
,因为后者为begin
/endconst_iterator
代码>函数。更改:至:
It works for
vector
but not forset
because the latter returnsconst_iterator
forbegin
/end
functions. Change:to: