Tôi muốn thực hiện hàm atoi () tại thời gian biên dịch (bằng ngôn ngữ C ++, bằng cách sử dụng tiêu chuẩn C ++ 11 hoặc C ++ 14). Vì vậy, nó sẽ có thể phân tích văn bản kèm theo dấu ngoặc kép dưới dạng số hoặc sửa lỗi. Cụ thể hơn, nó là một phần của hệ thống lớn hơn, có thể phân tích định dạng giống như printf tại thời gian biên dịch. Và tôi muốn phân chia các chuỗi định dạng trên các từ và nếu một số từ cụ thể có thể được biểu thị bằng số - số đầu ra thay vì chuỗi (phía sau cảnh là lớp serializer, có thể tuần tự hóa các số hiệu quả hơn so với các chuỗi và nhiều hơn quan trọng, trình giải mã sau đó không nên cố phân tích từng chuỗi dưới dạng số, vì tất cả các chữ số được in bên trong chuỗi định dạng luôn được biểu diễn dưới dạng số, nhưng không phải là chuỗi) ...
Theo tôi biết hai có thể có hai cách tiếp cận để giải quyết nhiệm vụ:
1) bằng cách sử dụng các hàm constexpr;
2) bằng siêu lập trình mẫu.
Cách nào có thể tốt hơn? Tôi đã thử cách đầu tiên và tôi có thể thấy có nhiều trở ngại theo cách này: đặc biệt là một vài hạn chế liên quan đến c ++ 11. Có vẻ như thứ hai có thể thích hợp hơn, nhưng nó đòi hỏi một số thủ thuật (bạn cần tách chuỗi c để tách các ký tự bằng cách sử dụng toán tử "", được hỗ trợ trong gcc bắt đầu từ c ++ 14 và trong tiếng kêu bắt đầu từ c ++ 11 ). Ngoài ra giải pháp hoàn toàn dựa trên TMP có thể quá lớn và quá rối.
Dưới đây là giải pháp của tôi, tôi rất vui khi nghe một số gợi ý về nó.
http://coliru.stacked-crooking.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;
}
Về cơ bản tôi muốn hỏi, làm thế nào tôi có thể chuyển đổi theo số thời gian biên dịch (như "42") được viết bằng dấu ngoặc kép trong giá trị của loại tích phân. Giải pháp của tôi trông quá cồng kềnh.