How do I generate an integer from a string literal at compile-time?
在 C 中,是否可以仅使用编译时工具从字符串文字生成整数?
例如,如果我们只有文字”6″,有没有办法将它用作模板参数,例如
我知道基于
1
2 3 |
template <int N> constexpr char get_char(const char s[N], int n) {
return s[n]; } |
但是
这只是为了实验,所以欢迎疯狂的想法。
显然 gcc 允许将
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
#include <boost/preprocessor/repetition/enum.hpp>
template <const char… characters> template <const char head, const char… rest> template <> #define GET_NTH_CHARACTER(z, n, data) data[n] int main() |
但它不会在 clang 上编译,它说 “non-type template argument of type //’const char//’ is not an integer constant expression”。
它真正的作用是将字符串文字
1
|
GetIntegerTemplate<‘1’, ‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’>::value
|
然后调用
将列表转换为整数 1234567。 string → char 文字步骤可能涉及非标准行为,可能在 g 之外不起作用(即比
(转自我的另一个答案)
如果您不介意将 //’string literal//’ 的概念定义从例如
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
#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 typedef mpl::vector10< template<typename IntegralT, typename PowerT> template<typename IntegralT, std::size_t Power> template<typename IntegralT> template<typename IntegralT> template<typename IntegralT, typename StringT> template<typename IntegralT, typename StringT> template<typename ExtractedStringT> template<typename ExtractedStringT> template<typename IntegralT, typename ExtractedStringT> template<typename IntegralT, typename StringT> typedef typename extract_actual_string< typedef typename accumulate_digits< public: template<typename IntegralT, typename StringT> template<typename IntegralT, int C0, int C1 = 0, int C2 = 0, |
用法如下:
1
2 3 4 |
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; |
实现了对负数的支持,不支持溢出检测(但您的编译器可能会给出警告)。
我不确定这是否可能,但这是你可以尝试的。
您可以将字符数字的值减去 //’0//’ 以获得数字形式的值。
喜欢:
1
2 |
char a = ‘5’;
int num = a – ‘0’; |
这将解决您的问题一位数。
要求解一个多位数的数字(如”12345″),您必须循环所有数字并对结果求和(每个数字乘以 10^pos)。
这在执行时很容易做到,但在编译时就不那么简单了。
“compile time recursion” 可能是你的朋友。老实说,我想不出任何使用它的解决方案,但你可能会找到一个。
祝你好运!
也许?
1
2 3 4 5 6 7 |
template<int C>
struct get_char { static const int value = C – 48; }; static_assert(get_char<‘0’>::value == 0,""); |
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/268935.html