- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想在编译时实现atoi()函数(在C++语言中,使用C++11或C++14标准)。因此它应该能够将双引号中的文本解析为数字,或者报告错误。更具体地说,它是更大系统的一部分,能够在编译时解析类似 printf 的格式。我想分割单词上的格式字符串,如果某个特定单词可以用数字表示 - 输出数字而不是字符串(幕后是序列化器类,它可以比字符串更有效地序列化数字,并且更有效)重要的是,反序列化器不应尝试将每个字符串解析为数字,因为格式字符串中打印的所有数字始终表示为数字,而不是字符串)...
据我所知,可以有两种方法来解决该任务:
1) 通过使用 constexpr 函数;
2) 通过模板元编程。
哪种方式可以更好?我尝试过第一种方法,我可以看到这种方法有很多障碍:尤其是与 c++11 相关的限制。看起来第二个可能更可取,但它需要一些技巧(您需要使用 of 运算符“”将 c 字符串分割为单独的字符,从 c++14 开始的 gcc 以及从 c++11 开始的 clang 中支持该功能)。而且完全基于TMP的解决方案可能会太大而且太困惑。
以下是我的解决方案,我很高兴听到一些有关它的建议。
http://coliru.stacked-crooked.com/a/0b8f1fae9d9b714b
#include <stdio.h>
template <typename T> struct Result
{
T value;
bool valid;
constexpr Result(T v) : value(v), valid(true) {}
constexpr Result() : value(), valid(false) {}
};
template <typename T>
constexpr Result<T> _atoi_oct(const char *s, size_t n, T val, int sign)
{
return n == 0 ? Result<T>(sign < 0 ? -val : val)
: *s >= '0' && *s <= '7'
? _atoi_oct(s+1, n-1, val*T(010) + *s - '0', sign)
: Result<T>();
}
template <typename T>
constexpr Result<T> _atoi_dec(const char *s, size_t n, T val, int sign)
{
return n == 0 ? Result<T>(sign < 0 ? -val : val)
: *s >= '0' && *s <= '9'
? _atoi_dec(s+1, n-1, val*T(10) + *s - '0', sign)
: Result<T>();
}
template <typename T>
constexpr Result<T> _atoi_hex(const char *s, size_t n, T val, int sign)
{
return n == 0 ? Result<T>(sign < 0 ? -val : val)
: *s >= '0' && *s <= '9'
? _atoi_hex(s+1, n-1, val*T(0x10) + *s - '0', sign)
: *s >= 'a' && *s <= 'f'
? _atoi_hex(s+1, n-1, val*T(0x10) + *s - 'a' + 10, sign)
: *s >= 'A' && *s <= 'F'
? _atoi_hex(s+1, n-1, val*T(0x10) + *s - 'A' + 10, sign)
: Result<T>();
}
template <typename T>
constexpr Result<T> _atoi_zero(const char *s, size_t n, int sign = 1)
{
return n == 0 ? Result<T>()
: *s >= '0' && *s <= '7'
? _atoi_oct(s+1, n-1, T(*s - '0'), sign)
: *s == 'x' || *s == 'X'
? _atoi_hex(s+1, n-1, T(0), sign)
: Result<T>();
}
template <typename T>
constexpr Result<T> _atoi_sign(const char *s, size_t n, int sign = 1)
{
return n == 0 ? Result<T>()
: *s == '0'
? _atoi_zero<T>(s+1, n-1, sign)
: *s > '0' && *s <= '9'
? _atoi_dec(s+1, n-1, T(*s - '0'), sign)
: Result<T>();
}
template <typename T>
constexpr Result<T> _atoi_space(const char *s, size_t n)
{
return n == 0 ? Result<T>()
: (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r' || *s == '\v')
? _atoi_space<T>(s+1, n-1)
: *s == '-'
? _atoi_sign<T>(s+1, n-1, -1)
: *s == '+'
? _atoi_sign<T>(s+1, n-1)
: *s == '0'
? _atoi_zero<T>(s+1, n-1)
: _atoi_dec(s, n, T(0), 1);
}
template <size_t N> void pstr(const char (&s)[N])
{
printf("s '%.*s'\n", int(N-1), s);
}
template <typename Str>
__attribute__((always_inline))
void _atoi(Str s)
{
constexpr auto result = _atoi_space<long>(s.cstr(), sizeof(s.cstr())-1);
if (result.valid)
printf("i %ld\n", result.value);
else
pstr(reinterpret_cast<const char (&)[sizeof(s.cstr())]>(s.cstr()));
}
#define atoi(STR) _atoi([]() { \
struct S { \
static constexpr const char (&cstr())[sizeof(STR)] { return STR; } \
}; \
return S(); \
}())
int main()
{
atoi("42");
atoi("-1");
atoi("+1");
atoi("010");
atoi("-0x10");
atoi("--1");
atoi("x");
atoi("3x");
return 0;
}
基本上我想问,如何在编译时将双引号中写的数字(如“42”)转换为整数类型的值。我的解决方案看起来太麻烦了。
最佳答案
使用 C++14,我们可以摆脱宏和一些三元运算符。这是我的做法,代码应该是不言自明的(我还添加了一些注释)。下面的代码也可以找到here (带有一些示例)用于编译器比较。
#include <cstdint>
#include <iostream>
template <typename T>
struct Result
{
T value{};
bool valid = false;
constexpr explicit Result(T v) : value(v), valid(true) {}
constexpr Result() = default;
};
// converts upper case chars to lower case
constexpr char to_lower(char c)
{
return c >= 'A' && c <= 'Z'
? c - 'A' + 'a'
: c;
}
// converts a digit char to its numeric value (eg. 'F' -> 15)
constexpr int to_digit(char c)
{
c = to_lower(c);
return c >= 'a'
? c - 'a' + 10
: c - '0';
}
// checks whether the given digit fits in the given base (eg. 'A' in 16 (hex) -> true, but '9' in 8 (oct) -> false)
constexpr bool is_digit(char c, int base)
{
int digit = to_digit(c);
return 0 <= digit && digit < base;
}
namespace detail
{
// returns true if c is a sign character (+ or -), sign will hold a valid factor (1 or -1) regardless of the return value
constexpr bool get_sign(char c, int& sign)
{
if (c == '-')
{
sign = -1;
return true;
}
else
{
sign = 1;
return c == '+';
}
}
// adds a digit to the right side of the a number
template <typename T>
constexpr T append_digit(T value, int base, int digit)
{
return value * base + digit;
}
// create the actual number from the given string
template <typename T>
constexpr T construct_integral(const char* str, std::size_t size, int base)
{
T value = 0;
for (std::size_t i = 0; i < size; i++)
value = append_digit(value, base, to_digit(str[i]));
return value;
}
// how many chars are necessary to specify the base (ex. hex -> 0x -> 2)
constexpr std::size_t get_base_offset(int base)
{
if (base == 8) return 1;
if (base == 16) return 2;
return 0;
}
// gets the base value according to the number prefix (eg. 0x -> 16 (hex))
constexpr int get_base(const char* str, std::size_t size)
{
return str[0] == '0'
? size > 2 && to_lower(str[1]) == 'x'
? 16
: 8
: 10;
}
// checks whether all digits in the string can fit in the given base
constexpr bool verify_base(const char* str, std::size_t size, int base)
{
for (std::size_t i = 0; i < size; i++)
if (!is_digit(str[i], base))
return false;
return true;
}
}
template <typename T = int>
constexpr Result<T> to_integral(const char* str, std::size_t size)
{
using namespace detail;
// remove the sign from the string
auto sign = 0;
if (get_sign(str[0], sign))
{
++str;
--size;
}
// get the base and remove its prefix from the string
auto base = get_base(str, size);
auto offset = get_base_offset(base);
str += offset;
size -= offset;
// check if the string holds a valid number with respect to its base
if (!verify_base(str, size, base))
return {};
// create the number and apply the sign
auto unsigned_value = construct_integral<T>(str, size, base);
return Result<T>(unsigned_value * sign);
}
template <typename T = int, std::size_t N>
constexpr Result<T> to_integral(const char(&str)[N])
{
static_assert(N > 1, "Empty strings are not allowed");
return to_integral<T>(str, N - 1);
}
C++17 可以通过使用 std::string_view
进一步减少代码量。您的Result<T>
也可以替换为 std::optional
.
关于c++ - 编译时文本到数字的翻译 (atoi),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59535265/
是否有任何库或框架旨在促进从另一种成熟的编程语言中构建项目? 在 C++、java 等编程语言中指定逻辑、集合和复杂规则非常容易,但在 Makefile 中完成这些事情似乎是一场艰苦的战斗。我还没有深
我有这段代码可以用 clang 编译得很好(即使使用 -Weverything),但是 gcc 会发出错误。 #include #include #include using namespace
我有以下 block 头文件 BKE_mesh.h: /* Connectivity data */ typedef struct IndexNode { struct IndexNode *
我在我的一个项目中遇到了一个奇怪的问题。我的代码库依赖于一个外部库,其中包含一个名为 Dataset 的类. Dataset类私有(private)继承自 std::vector (其中 Sample
当使用 gcc、g++ 或 make 在终端中编译一个小型 C 或 C++ 项目时,我收到以下错误: /tmp/ccG1caGi.o: In function `main': main.c:(.tex
我正在尝试从 CVS 为 Windows 上的 Emacs 23.1.50 编译 CEDET,但在“第 6 步:打开 EDE...”时出现错误:“defvar:作为变量的符号值是无效的:cedet-m
我正在(重新)学习编程,我从 C 开始。我的 IDE(如果我可以这么说)是 Windows7 上的 cygwin(32 位)和 Visual-Studio 2010。我总是编译我用 gcc (cygw
我喜欢在模板类中使用本地类来执行类似“static if”的构造。但是我遇到了 gcc 4.8 不想编译我的代码的问题。但是 4.7 可以。 这个例子: #include #include #in
我有一个项目,必须仅使用 java 1.4 进行编译。但我计划使用mockito 编写一些单元测试。我想要一种在 pom 中指定的方法,以便 src/main/java 使用 jdk 1.4 编译,但
我想了解 PHP 编译过程是如何工作的。 假设我有一个名为funcs.php 的文件并且这个文件有三个函数,如果我include 或require 它,所有的在文件加载期间编译三个函数?或者源代码会被
编译工具链 我们写程序的时候用的都是集成开发环境 (IDE: Integrated Development Environment),集成开发环境可以极大地方便我们程序员编写程序,但是配置起来
当我编写一些 Scala 代码时,在尝试编译代码时收到一条奇怪的错误消息。我将代码分解为一个更简单的代码(从语义的角度来看这完全没有意义,但仍然显示了错误)。 scala> :paste // Ent
我正在编译一个 SCSS 文件,它似乎删除了我的评论。我可以使用什么命令来保留所有评论? >SASS input.scss output.css 我在 SCSS 中看到两种类型的注释。 // Comm
这是我的代码: #include typedef struct { const char *description; float value; int age; } swag
当您编译 grails war 时,我知道 .groovy 代码被编译为字节码类文件,但我不明白容器(例如 tomcat)如何在请求 GSP 时知道如何编译它们。容器了解 GSP 吗?安装在服务器上的
我正在努力将多个文件编译成一个通用程序。我收到一个错误: undefined reference to 'pi' 这是我的代码和 Makefile 的框架。我做错了什么?谢谢! 文件:calcPi.c
我尝试使用 LD_PRELOAD 来 Hook sprintf function ,所以我将打印到缓冲区的结果: #define _GNU_SOURCE #include #include int
我正在寻找最简单的方法来自动将 CoffeeScript 重新编译为 JS。 阅读documentation但仍然很难得到我想要的东西。 我需要它来监视文件夹 src/ 中的任何 *.coffee 文
我想使用定制waveformjs 。我发现this on SO但是,我不知道如何编译/安装波形来开始。我从 GitHub 克隆它并进行了更改,但是我不知道如何将其转换为 .js 文件。 最佳答案 为了
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我是一名优秀的程序员,十分优秀!