(przeksięgowanie z another answer of mine)
Jeśli nie przeszkadza zmieniając koncepcyjnej definicji „łańcucha dosłowny” od np
do '4258','97'
, następnie można użyć Boost. MPL „s boost::mpl::string<>
do osiągnięcia tego celu:
#include <cstddef>
#include <boost/type_traits/is_integral.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/is_signed.hpp>
#include <boost/mpl/and.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/mpl/char.hpp>
#include <boost/mpl/contains.hpp>
#include <boost/mpl/end.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/find_if.hpp>
#include <boost/mpl/fold.hpp>
#include <boost/mpl/front.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/mpl/integral_c.hpp>
#include <boost/mpl/minus.hpp>
#include <boost/mpl/negate.hpp>
#include <boost/mpl/next.hpp>
#include <boost/mpl/not.hpp>
#include <boost/mpl/pair.hpp>
#include <boost/mpl/placeholders.hpp>
#include <boost/mpl/plus.hpp>
#include <boost/mpl/pop_front.hpp>
#include <boost/mpl/push_back.hpp>
#include <boost/mpl/reverse_fold.hpp>
#include <boost/mpl/size_t.hpp>
#include <boost/mpl/string.hpp>
#include <boost/mpl/times.hpp>
#include <boost/mpl/vector.hpp>
namespace details
{
namespace mpl = boost::mpl;
typedef mpl::vector10<
mpl::char_<'0'>, mpl::char_<'1'>, mpl::char_<'2'>, mpl::char_<'3'>,
mpl::char_<'4'>, mpl::char_<'5'>, mpl::char_<'6'>, mpl::char_<'7'>,
mpl::char_<'8'>, mpl::char_<'9'>
> valid_chars_t;
template<typename IntegralT, typename PowerT>
struct power_of_10;
template<typename IntegralT, std::size_t Power>
struct power_of_10<IntegralT, mpl::size_t<Power> > : mpl::times<
power_of_10<IntegralT, mpl::size_t<Power - 1u> >,
mpl::integral_c<IntegralT, 10>
> { };
template<typename IntegralT>
struct power_of_10<IntegralT, mpl::size_t<1u> >
: mpl::integral_c<IntegralT, 10>
{ };
template<typename IntegralT>
struct power_of_10<IntegralT, mpl::size_t<0u> >
: mpl::integral_c<IntegralT, 1>
{ };
template<typename IntegralT, typename StringT>
struct is_negative : mpl::and_<
boost::is_signed<IntegralT>,
boost::is_same<
typename mpl::front<StringT>::type,
mpl::char_<'-'>
>
> { };
template<typename IntegralT, typename StringT>
struct extract_actual_string : mpl::eval_if<
is_negative<IntegralT, StringT>,
mpl::pop_front<StringT>,
mpl::identity<StringT>
> { };
template<typename ExtractedStringT>
struct check_valid_characters : boost::is_same<
typename mpl::find_if<
ExtractedStringT,
mpl::not_<mpl::contains<valid_chars_t, mpl::_> >
>::type,
typename mpl::end<ExtractedStringT>::type
> { };
template<typename ExtractedStringT>
struct pair_digit_with_power : mpl::first<
typename mpl::reverse_fold<
ExtractedStringT,
mpl::pair<mpl::vector0<>, mpl::size_t<0> >,
mpl::pair<
mpl::push_back<
mpl::first<mpl::_1>,
mpl::pair<mpl::_2, mpl::second<mpl::_1> >
>,
mpl::next<mpl::second<mpl::_1> >
>
>::type
> { };
template<typename IntegralT, typename ExtractedStringT>
struct accumulate_digits : mpl::fold<
typename pair_digit_with_power<ExtractedStringT>::type,
mpl::integral_c<IntegralT, 0>,
mpl::plus<
mpl::_1,
mpl::times<
mpl::minus<mpl::first<mpl::_2>, mpl::char_<'0'> >,
power_of_10<IntegralT, mpl::second<mpl::_2> >
>
>
> { };
template<typename IntegralT, typename StringT>
class string_to_integral_impl
{
BOOST_MPL_ASSERT((boost::is_integral<IntegralT>));
typedef typename extract_actual_string<
IntegralT,
StringT
>::type ExtractedStringT;
BOOST_MPL_ASSERT((check_valid_characters<ExtractedStringT>));
typedef typename accumulate_digits<
IntegralT,
ExtractedStringT
>::type ValueT;
public:
typedef typename mpl::eval_if<
is_negative<IntegralT, StringT>,
mpl::negate<ValueT>,
mpl::identity<ValueT>
>::type type;
};
}
template<typename IntegralT, typename StringT>
struct string_to_integral2
: details::string_to_integral_impl<IntegralT, StringT>::type
{ };
template<typename IntegralT, int C0, int C1 = 0, int C2 = 0,
int C3 = 0, int C4 = 0, int C5 = 0, int C6 = 0, int C7 = 0>
struct string_to_integral : string_to_integral2<
IntegralT,
boost::mpl::string<C0, C1, C2, C3, C4, C5, C6, C7>
> { };
Wykorzystanie wyglądałby następująco:
int i = string_to_integral<int, '4258','97'>::value;
// or
typedef boost::mpl::string<'4258','97'> str_t;
unsigned j = string_to_integral2<unsigned, str_t>::value;
Wsparcie dla liczb ujemnych jest realizowany, wsparcie dla wykrywania przepełnienia nie jest (ale kompilator będzie prawdopodobnie dać ostrzeżenie) .
Co oznacza "większość kompilatorów"? Jeśli "większość kompilatorów" zawiera prawdopodobnie najpopularniejsze kompilatory (gcc i Visual C++), to odpowiedź brzmi, że nie można tego zrobić. –
Dlaczego po prostu nie pisać 6 bez cudzysłowów? – littleadv
Może to działać, jeśli użyjesz literałów znaków 'GET_INTEGER ('6', '7', '8')', ale nie sądzę, że literały łańcuchowe będą działały. – kennytm