如何在编译时从字符串文字生成整数
How do I generate an integer from a string literal at compile-time?
在C++中,是否可以仅使用编译时工具从字符串文字生成整数?
例如,如果我们只有文字"6",是否有某种方法可以将其用作模板参数,如std::array<GET_INTEGER("6")> a;
?
我知道基于constexpr
的技术,例如:
template <int N> constexpr char get_char(const char s[N], int n) {
return s[n];
}
然而,constexpr
在大多数编译器上还没有准备好,所以我正在寻找可能使用宏和TMP的解决方案。
这只是为了试验,所以疯狂的想法是受欢迎的。
显然,gcc允许"abcd"[3]
被解释为'd'
,这允许它工作(至少在g++-4.6和4.7上):
#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");
}
但它不会在clang上编译,clang表示"const-char类型的非类型模板参数不是一个整数常量表达式"。
它真正做的是将字符串文字"1234567"
分解为字符文字'1', '2', '3', '4', '5', '6', '7'
的列表。实例化
GetIntegerTemplate<'1', '2', '3', '4', '5', '6', '7'>::value
然后调用以将列表转换为整数1234567。字符串→字符文字步骤可能涉及非标准行为,在g++之外可能不起作用(即比constexpr
更差☺),但CCD_ 9是可移植的。
(从我的另一个答案重新测试)
如果您不介意更改"字符串文字"的概念定义,例如"425897"
到'4258','97'
,然后您可以使用Boost.MPL的boost::mpl::string<>
来实现这一点:
#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>
> { };
用法如下:
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;
实现了对负数的支持,但不支持溢出检测(但编译器可能会发出警告)。
也许?
template<int C>
struct get_char
{
static const int value = C - 48;
};
static_assert(get_char<'0'>::value == 0, "");
我不确定这是否可能,但这是你可以尝试的。
您可以将字符数字的值递减"0",以获得数字形式的值。
类似:
char a = '5';
int num = a - '0';
这可以解决你一位数的问题。
要求解一个有多个数字的数字(如"12345"),必须循环所有数字并对结果求和(每个数字乘以10^pos)。
这在执行时很容易做到,但在编译时就没那么简单了。
"编译时递归"可能是你的朋友。老实说,我想不出任何使用它的解决方案,但你可能会找到一个。
祝你好运!
- 如何反转整数参数包
- enum是C++中的宏变量还是整数变量
- 努力将整数转换为链表。不知道我在这里做错了什么
- 整数不会重复超过随机数
- 在C++中手动调整数组大小
- 检查输入是否不是整数或数字
- C++使用整数的压缩数组初始化对象
- 提升灵气整数,默认值为文字
- 将整数(文字)与函数相关联,让呼叫者查询拖鞋的数量
- C++ 如何将文字与整数连接起来
- 初始化char数组和具有整数文字的char时的差异
- c++中整数文字的内存地址c++中不允许使用指向整数文本的
- 字符串文字和整数常数的问题
- 从文字字符串生成编译时常量整数
- _mm_extract_epi8(..) 内部函数,采用非文字整数作为参数
- 如何将整数变量连接到字符串文字
- 如何在编译时从字符串文字生成整数
- 为什么用整数文字调用重载的 ambig(long) 和 ambig(无符号 long)是不明确的
- __int128@min负值的UDL(用户定义的文字)整数溢出
- C++ 关于整数文字的入门段落,需要有人澄清一些要点