有没有比存在allocator_type更好的方法来区分可调整大小的容器
Is there a better way to distinguish resizable containers than presence of allocator_type?
>我有模板重载用于operator>>()
,我需要区分可以调整大小的容器,例如vector
,和不能调整大小的容器,例如array
。我目前只是使用allocator_type
特征的存在(请参阅下面的代码)--它工作得很好--但想知道是否有更明确的方法来测试它。
template <class T>
struct is_resizable {
typedef uint8_t yes;
typedef uint16_t no;
template <class U>
static yes test(class U::allocator_type *);
template <class U>
static no test(...);
static const bool value = sizeof test<T>(0) == sizeof yes;
};
template <typename C>
typename boost::enable_if_c<
boost::spirit::traits::is_container<C>::value && is_resizable<C>::value,
istream &
>::type
operator>>(istream &ibs, C &c)
{
c.resize(ibs.repeat() == 0 ? c.size() : ibs.repeat());
for (typename C::iterator it = c.begin(); it != c.end(); ++it)
{
C::value_type v;
ibs >> v;
*it = v;
}
return ibs;
}
template <typename C>
typename boost::enable_if_c<
boost::spirit::traits::is_container<C>::value && !is_resizable<C>::value,
istream &
>::type
operator>>(istream &ibs, C &c)
{
for (typename C::iterator it = c.begin(); it != c.end(); ++it)
ibs >> *it;
return ibs;
}
测试一个容器是否resize
-able,你可能应该检查它是否具有resize()
功能。在 C++03 中,这看起来像:
template <typename T>
class has_resize
{
private:
typedef char yes;
struct no {
char _[2];
};
template <typename U, U>
class check
{ };
template <typename C>
static yes test(check<void (C::*)(size_t), &C::resize>*);
template <typename C>
static no test(...);
public:
static const bool value = (sizeof(test<T>(0)) == sizeof(yes));
};
是的。您需要定义/使用自定义特征(就像boost::spirit::traits
一样)。
分配器的存在与否并不能真正告诉您容器是否是固定大小的。非标准容器可能根本没有allocator_type
关联类型,但仍允许resize(...)
事实上,由于您有效地断言了一个允许的概念
C::resize(size_t)
你可以只使用表达式SFINAE
Modern C++ 有一个非常简洁的方式:
template <typename T, typename = int>
struct resizable : std::false_type {};
template <typename T>
struct resizable <T, decltype((void) std::declval<T>().resize(1), 0)> : std::true_type {};
演示
现在,如果您不需要在成员函数和名称为 resize
的成员变量之间消除歧义,则可以编写上述decltype
如下:
decltype( (void) &T::resize, 0 )
请注意,强制转换为 void
是为了处理类型重载逗号运算符并且泛化失败的情况(因此这只是一个比抱歉更好的安全策略)
感谢@Jarod42对另一个问题的帮助,我有一个适用于 C++98、C++03 和 C++11 的解决方案; g++ 和 VS2015。另外,对于问题儿童,std::vector<bool>
.
#define DEFINE_HAS_SIGNATURE(traitsName, funcName, signature)
template <typename U>
class traitsName
{
private:
typedef boost::uint8_t yes; typedef boost::uint16_t no;
template<typename T, T> struct helper;
template<typename T> static yes check(helper<signature, &funcName>*);
template<typename T> static no check(...);
public:
static const bool value = sizeof check<U>(0) == sizeof(yes);
}
DEFINE_HAS_SIGNATURE(has_resize_1, T::resize, void (T::*)(typename T::size_type));
DEFINE_HAS_SIGNATURE(has_resize_2, T::resize, void (T::*)(typename T::size_type,
typename T::value_type));
这是它的使用方式,如下所示。请注意,将检查resize()
的has_resize_1
和has_resize_2
成员函数签名。这是因为在 C++11 之前,resize()
有一个带有两个参数的签名,最后一个带有默认值;截至 C++11,它有两个签名 - 一个具有一个参数,另一个具有两个参数。此外,VS2015显然有三个签名 - 以上所有。解决方案只是始终检查两个签名。
可能有一种方法可以将这两个检查组合成一个类型特征,例如 has_resize<C>::value
.如果你知道,告诉我。
template <typename T>
typename boost::enable_if_c<
!boost::spirit::traits::is_container<T>::value,
xstream &>::type
operator>>(xstream &ibs, T &b)
{
return ibs;
}
template <typename C>
typename boost::enable_if_c<
boost::spirit::traits::is_container<C>::value &&
(has_resize_1<C>::value || has_resize_2<C>::value),
xstream &
>::type
operator>>(xstream &ibs, C &c)
{
typename C::value_type v;
ibs >> v;
return ibs;
}
template <typename C>
typename boost::enable_if_c<
boost::spirit::traits::is_container<C>::value &&
!(has_resize_1<C>::value || has_resize_2<C>::value),
xstream &
>::type
operator>>(xstream &ibs, C &c)
{
typename C::value_type v;
ibs >> v;
return ibs;
}
- 创建异构顶点数据数组的可移植方法
- 从非类型模板参数声明 constexpr 数组的可移植方法
- 如何创建可调整大小和固定大小的容器的变体
- 是否有提供可调整 dpi、可选文本和 CSS 支持的 HTML 到 PDF 渲染器?
- 将参数推送到调用堆栈 (C++) 的可移植方法
- 将添加的列初始化为可调整大小的 2D 向量
- 可滚动的背景,上面有可调整大小的Qt小部件
- 公开对象管理器对象的可接受方法?
- 用std::vector编写可调整大小的矢量时出现问题
- 使用固定的顶部坐标创建可调整大小的窗口
- 一种在编译时用C++根据printf格式检查参数的可移植方法
- 在C++中设置文件修改时间的可移植方法
- 灵活的可调整大小的阵列C++
- 如何使Qt小部件可调整大小
- 带有指针的可调整大小数组
- 可调整大小的动态二维阵列的更好解决方案
- 确定使用dlopen打开的动态库的路径的可移植方法
- wxWidgets可调整大小的窗格
- 在构造函数中限制可变模板的可接受方法
- 有没有比存在allocator_type更好的方法来区分可调整大小的容器