I have template overloads for operator>>()
where I need to distinguish between containers that can be resized, e.g., vector
, and containers that cannot, e.g., array
. I am currently just using the presence of an allocator_type
trait (see code, below)--and it works just fine--but was wondering if there is a more explicit way of testing this.
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;
}
Thanks to help from @Jarod42 on a separate question, I have a solution that works with C++98, C++03, and C++11; g++ and VS2015. Also, for the problem child,
std::vector<bool>
.This is how it's used, below. Notice that both the
has_resize_1
andhas_resize_2
member-function signatures forresize()
are checked. That's because before C++11,resize()
had a single signature with two parameters, the last with a default value; as of C++11, it has two signatures--one with one parameter and the other with two parameters. Moreover, VS2015 apparently has three signatures--all of the above. The solution is just to check for both signatures all the time.There is probably a way to combine the two checks into a single type trait, such as
has_resize<C>::value
. Tell me if you know.