如何在编译时从字符串文本生成整数? 在C++中,是否可以使用仅使用编译时间设施生成字符串的整数?< /p>

如何在编译时从字符串文本生成整数? 在C++中,是否可以使用仅使用编译时间设施生成字符串的整数?< /p>,c++,templates,c-preprocessor,string-literals,C++,Templates,C Preprocessor,String Literals,例如,如果我们只有文字“6”,是否有某种方法将其用作模板参数,如std::array a 我了解基于constexpr的技术,例如: template <int N> constexpr char get_char(const char s[N], int n) { return s[n]; } 模板constepr char get_char(const char s[N],int N){ 返回s[n]; } 然而,constexpr在大多数编译器上还没有准备好,所以我正在

例如,如果我们只有文字“6”,是否有某种方法将其用作模板参数,如
std::array a

我了解基于
constexpr
的技术,例如:

template <int N> constexpr char get_char(const char s[N], int n) {
  return s[n];
}
模板constepr char get_char(const char s[N],int N){
返回s[n];
}
然而,
constexpr
在大多数编译器上还没有准备好,所以我正在寻找可能使用宏和TMP的解决方案

这只是为了实验,所以疯狂的想法是受欢迎的。

也许吧

template<int C>
struct get_char
{
    static const int value = C - 48;
};

static_assert(get_char<'0'>::value == 0, "");
模板
结构获取字符
{
静态常数int值=C-48;
};
静态_断言(get_char::value==0,“”);
(从重新发布)

如果您不介意更改“字符串文字”的概念定义,例如
“425897”
“4258”和“97”
,然后您可以使用.s来完成此操作:

#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>
> { };
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
命名空间详细信息
{
名称空间mpl=boost::mpl;
typedef mpl::vector10<
mpl::char,mpl::char,mpl::char,mpl::char,
mpl::char,mpl::char,mpl::char,mpl::char,
mpl::char,mpl::char_
>有效字符;
模板
_10的结构功率_;
模板
结构幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次<
10的幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂次幂,
mpl::积分
> { };
模板
结构电源(共10个)
:mpl::积分
{ };
模板
结构电源(共10个)
:mpl::积分
{ };
模板
结构为负:mpl::and_<
boost::已签名,
boost::是一样的吗<
typename mpl::front::type,
mpl::char_
>
> { };
模板
结构提取\u实际\u字符串:mpl::eval\u if<
是否定的,
mpl::pop_front,
mpl::identity
> { };
模板
结构检查\u有效\u字符:boost::是否相同<
typename mpl::查找\u if<
提拔弦,
mpl::不是_
>::类型,
typename mpl::end::type
> { };
模板
带\u幂的结构对\u数字\u:mpl::first<
typename mpl::反向折叠<
拔出的弦,
mpl::pair,
mpl::pair<
mpl::推回<
首先,
mpl::pair
>,
mpl::下一步
>
>::类型
> { };
模板
结构累积数字:mpl::fold<
typename对\u数字\u与\u power::type,
mpl::积分,
mpl::plus<
mpl::_1,
mpl::次<
mpl::负,
10的功率
>
>
> { };
模板
类字符串\u到\u整数\u impl
{
BOOST_MPL_断言((BOOST::is_integral));
typedef typename提取\实际\字符串<
完整的,
斯特林特
>::类型ExtractedStringT;
BOOST_MPL_ASSERT((检查有效字符));
typedef typename累积数字<
完整的,
拔弦
>::类型值t;
公众:
typedef typename mpl::eval_if<
是否定的,
否定,
mpl::identity
>::类型类型;
};
}
模板
结构字符串\u到\u整数2
:详细信息::字符串\u到\u整数\u impl::类型
{ };
模板
结构字符串到整数:字符串到整数2<
完整的,
boost::mpl::string
> { };
用法如下所示:

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;
inti=string\u to\u integral::value;
//或
typedef boost::mpl::string stru\t;
无符号j=字符串\u到\u整数2::值;

实现了对负数的支持,但不支持溢出检测(但您的编译器可能会发出警告)。

显然,gcc允许
“abcd”[3]
被解释为
“d”
,这允许它工作(至少在g++-4.6和4.7上):


然后调用以将列表转换为整数1234567。弦→ char literal步骤可能涉及非标准行为,在g++之外可能无法工作(即比
constepr
☺), 但是,
GetIntegerTemplate::value
是可移植的。

我不确定这是否可行,但这是您可以尝试的

您可以将字符数字的值递减“0”以获得数字形式的值

比如:

这就解决了你一位数的问题

对于一个有许多数字的数字(如“12345”),您必须循环所有数字并将结果相加(每个数字乘以10^pos)

这在执行时很容易做到,但在编译时就没那么简单了

“编译时递归”可能是您在这里的朋友。老实说,我想不出任何使用它的解决方案,但您可能会找到一个


祝你好运!

什么是“大多数编译器”呢?如果“大多数编译器”包含了可能使用最广泛的编译器(gcc和Visual C++),那么答案是这是不可能的。为什么不直接写6,而不加引号呢?如果你使用字符文本
GET_INTEGER('6','7','8'),它就可以工作了
,但我认为字符串文字不起作用。@JamesMcNellis AFAIK,现在只有gcc支持constepr。(虽然我可能错了)这很有趣,但什么是
'4258'
?@kbok:
'4258','97'
是表示字符串文字
'425897'的方式
在某种程度上可用于
boost::mpl::string
@ildjarn:该示例代码需要所有这些boost包含吗?我想我记得为什么我讨厌使用boost…@kbok:
'1234'
被称为多字符文字。它们的表示形式为
char
ar
#include <boost/preprocessor/repetition/enum.hpp>

template <const char... characters>
struct GetIntegerTemplate;

template <const char head, const char... rest>
struct GetIntegerTemplate<head, rest...>
{
    typedef GetIntegerTemplate<rest...> Prev;
    enum
    {
        power = Prev::power * 10,
        value = (head - '0') * Prev::power + Prev::value
    };
};

template <>
struct GetIntegerTemplate<>
{
    enum
    {
        power = 1,
        value = 0
    };
};

#define GET_NTH_CHARACTER(z, n, data) data[n]
#define GET_INTEGER(length, the_string) GetIntegerTemplate<BOOST_PP_ENUM(length, GET_NTH_CHARACTER, the_string)>::value

int main()
{
    static_assert(GET_INTEGER(7, "1234567") == 1234567, "oops");
}
GetIntegerTemplate<'1', '2', '3', '4', '5', '6', '7'>::value
char a = '5';
int num =  a - '0';