What overhead is there in performing an identity boost::lexical_cast?
-
01-07-2021 - |
質問
Given a function such as:
template< typename T >
void function1( const T &t )
{
function2( boost::lexical_cast<std::string>(t) );
}
What kind of overhead is incurred if the type passed to function1
is already a std::string
?
Does the overhead vary, depending on the type I'm lexical_cast
-ing to?
Is it superfluous to make an overloaded function to bypass the cast? E.g.:
void function1( const std::string &t )
{
function2( t );
}
template< typename T >
void function1( const T &t )
{
function1( boost::lexical_cast<std::string>(t) );
}
The version of boost may be relevent to your answer, as I understand that lexical_cast
has received a few optimizations across revisions.
解決
Since the documentation doesn't offer anything on this topic, I dug into the lexical_cast
source (1.51.0) and found that it does some compile-time checking on the types and decides a specific "caster class" that does the conversion. In case source and target are the same, this "caster class" will simply return the input.
Pseudo-codified and simplified from source (boost/lexical_cast.hpp:2268
):
template <typename Target, typename Source>
Target lexical_cast(const Source &arg)
{
static if( is_character_type_to_character_type<Target, src> ||
is_char_array_to_stdstring<Target, src> ||
is_same_and_stdstring<Target, src> )
// ^-- optimization for std::string to std::string and similar stuff
{
return arg;
}
else
{
/* some complicated stuff */
}
}
I can't directly see any optimizations for other identity casts, though, and looking through the normally selected lexical_cast_do_cast
"caster class" is making my head hurt. :(
他のヒント
http://www.boost.org/doc/libs/1_51_0/doc/html/boost_lexical_cast/performance.html
Consider this link, string to string is very fast.
All the tests measure execution speed in milliseconds for 10000 iterations of the following code blocks:
typedef BOOST_DEDUCED_TYPENAME ::boost::type_traits::ice_or<
::boost::detail::is_xchar_to_xchar<Target, src >::value,
::boost::detail::is_char_array_to_stdstring<Target, src >::value,
::boost::type_traits::ice_and<
::boost::is_same<Target, src >::value,
::boost::detail::is_stdstring<Target >::value
>::value
> shall_we_copy_t;
In our case shall_we_copy_t::value
will be true, since 3-rd case work for us (Target
and src
are equal types and Target
type is std::basic_string
).
typedef BOOST_DEDUCED_TYPENAME ::boost::mpl::if_c<
shall_we_copy_t::value,
::boost::detail::lexical_cast_copy<src >,
BOOST_DEDUCED_TYPENAME ::boost::mpl::if_c<
shall_we_copy_with_dynamic_check_t::value,
::boost::detail::lexical_cast_dynamic_num<Target, src >,
::boost::detail::lexical_cast_do_cast<Target, src >
>::type
>::type caster_type;
Since, shall_we_copy_t::value
is true, our caster_type will be lexical_cast_copy
return caster_type::lexical_cast_impl(arg);
So, will be called lexical_cast_copy::lexical_cast_impl
, which is very simple
template <typename Source>
struct lexical_cast_copy
{
static inline Source lexical_cast_impl(const Source &arg)
{
return arg;
}
};