|
Boost Users : |
Subject: [Boost-users] Ranges and primitive arrays and argument forwarding
From: John M. Dlugosz (mpbecey7gu_at_[hidden])
Date: 2011-07-11 09:13:07
In a nutshell, I want to use ranges to unify several different ways of representing
"strings" in the program. This includes subranges of an existing sequence, so for
consistancy a "fixed" sized container does not need a nul termination but can fill the
container completely. The point here is that I want to treat arrays differently from
pointers, which is unlike boost::as_literal.
The idea is that I can apply a pre-conditioning function to any supported type, and get a
iterator_range back out. Here is an example of a trivial function to test it out, that
just returns the length:
namespace internal {
template <typename RangeT>
size_t Strlen (RangeT s)
{
return boost::size(s);
}
}
template <typename T>
size_t Strlen (T s)
{
return internal::Strlen (internal::as_literal(s));
}
For a more complex function, every argument that is meant to be a generalized "string"
will be so-wrapped, and pass on to the underlying internal form which expects that they
are all Ranges.
The conditioning needed is almost the same as boost::as_literal, so I copied and modified
that:
template <typename CharT>
inline boost::iterator_range<CharT> measure_fixed (CharT* p, std::size_t capacity)
{
// The deduced CharT will include the const if called on a const array.
Char* found= std::find (p, p+capacity, CharT(0));
// the find algorithm naturally does what I want, returning the same 'end' if not
found.
return boost::iterator_range<CharT> (p, found);
}
// Copied directly from Boost: pointers and containers
template< class Range >
inline boost::iterator_range<typename boost::range_iterator<Range>::type>
as_literal( Range& r )
{
return boost::range_detail::make_range( r, boost::range_detail::is_char_ptr(r) );
}
// Ditto, with const. Duplication needed because && not available on VS8
template< class Range >
inline boost::iterator_range<typename boost::range_iterator<const Range>::type>
as_literal( const Range& r )
{
return boost::range_detail::make_range( r, boost::range_detail::is_char_ptr(r) );
}
// Actual arrays: I want to treat differently from pointers.
template <typename Char, std::size_t sz >
inline boost::iterator_range<Char*> as_literal( Char (&arr)[sz] )
{
return measure_fixed (arr, sz);
}
// Duplicate needed for const form.
template< typename Char, std::size_t sz >
inline boost::iterator_range<const Char*> as_literal( const Char (&arr)[sz] )
{
return measure_fixed (arr, sz);
}
However, I find that it is NOT distinguishing arrays:
char cA[4]= { 'a', 'b', 'c', 'd' }; // fixed size array, no termination
size_t result= Strlen (cA);
This is calling the regular form, not the arragy form. The top-level function's call to
internal::as_literal is going to the first form, not the third. The parameter, r, is of
type char*& from what the debugger tells me, so the template argument Range must be
deduced as char*. The original Strlen see s as a char*, so it's already lost it at this
point.
If I have to write every top-level function to take separate array and non-array template
forms, besides being less elegant it will be a combinitational explosion on functions that
take multiple arguments.
Is there a way around this that work in Visual Studio 2005 (a.k.a. VS8)?
When the project finally moves to a newer compiler, does rvalue references ("perfect
forwarding") fix this issue, or is it still losing the arrayness by design?
Thanks,
âJohn
Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net