TODO reminder constexpr
TODO reminder constexpr
我看到一个人创建了一个类似static_assert的东西,它使用 DATE 来创建 TODO 代码部分的提醒,我喜欢这个想法,所以我尝试实现它,当我的编译器不喜欢我的接近时,问题就来了,它说:
- 过于复杂的 constexpr 函数
- 表达式应具有常量值
我使用的是启用了c ++ 17功能的Visual studio 2017,关键字CONSTEXPR是一个宏,如果编译器支持,则用constexpr替换
它法典:
namespace private_TODO
{
CONSTEXPR bool is_digit(char c)
{
return c <= '9' && c >= '0';
}
CONSTEXPR unsigned stoi_impl(const char* str, int rec = 0, int value = 0)
{
return rec != 0 ?
is_digit(*str) ?
stoi_impl(str + 1, rec--, (*str - '0') + value * 10)
: throw "Compile-time-error: not a digit"
: value;
}
CONSTEXPR unsigned stoi(const char* str, int maxIter)
{
return stoi_impl(str, maxIter);
}
CONSTEXPR unsigned year(const char* str)
{
return stoi(str, 4);
}
CONSTEXPR bool str_cmp(const char* str, const char* str2, unsigned sz)
{
return sz != 0 ?
*str == *str2 ? str_cmp(str + 1, str2 + 1, --sz)
: false
: true;
}
CONSTEXPR unsigned month(const char* str)
{
return str_cmp(str, "Jan", 3) ? 1 :
str_cmp(str, "Feb", 3) ? 2 :
str_cmp(str, "Mar", 3) ? 3 :
str_cmp(str, "Apr", 3) ? 4 :
str_cmp(str, "May", 3) ? 5 :
str_cmp(str, "Jun", 3) ? 6 :
str_cmp(str, "Jul", 3) ? 7 :
str_cmp(str, "Aug", 3) ? 8 :
str_cmp(str, "Set", 3) ? 9 :
str_cmp(str, "Oct", 3) ? 10 :
str_cmp(str, "Nov", 3) ? 11 :
str_cmp(str, "Dec", 3) ? 12 :
throw "Compile-time error: Not a month!";
}
CONSTEXPR unsigned day(const char* str)
{
return stoi(str, 2);
}
CONSTEXPR unsigned str_size(const char* str, unsigned value = 0)
{
return *str != 0 ?
str_size(str++, value++)
: value;
}
CONSTEXPR unsigned total(const char* str)
{
return (str_size(str) == 11 && str[3] == ' ' && str[6] == ' ') ?
year(str + 7) * 512 + month(str) * 32 + day(str + 4)
: throw "invalid string";
}
}
#define TODO(DATE, MESSAGE)
static_assert(::private_TODO::total(__DATE__) < ::private_TODO::total(DATE), MESSAGE)
void test()
{
TODO("NOV 16 2017", "THIS SHOULD THROW"); //11/16/17 is when I tested
}
我不明白为什么说表达式应该具有常量值,因为我认为一切都是常量,是的,它们是复杂的函数,我希望如果有人可以帮助我降低这个函数的复杂性 de
编辑:其中一个错误来自str_size它说无法将其评估为常量
我终于用string_view类做到了
using namespace std::string_literals;
using namespace std::string_view_literals;
/* TODO reminders */
namespace private_TODO
{
CONSTEXPR bool is_digit(char c)
{
return c <= '9' && c >= '0';
}
CONSTEXPR unsigned stoi_impl(const std::string_view& str, int value = 0)
{
return str.size() != 0 ?
is_digit(str[0]) ?
stoi_impl(str.substr(1, str.size() - 1), (str[0] - '0') + value * 10)
: throw "Compile-time-error: not a digit"
: value;
}
CONSTEXPR unsigned stoi(const std::string_view& str)
{
return stoi_impl(str);
}
CONSTEXPR bool str_cmp(const std::string_view& str, const std::string_view& str2, unsigned sz = 0)
{
return sz != str.size() ?
str[sz] == str2[sz] ?
str_cmp(str, str2, ++sz)
: false
: true;
}
CONSTEXPR unsigned month(const std::string_view& str)
{
return
str_cmp(str, "Jan"sv) ? 1 :
str_cmp(str, "Feb"sv) ? 2 :
str_cmp(str, "Mar"sv) ? 3 :
str_cmp(str, "Apr"sv) ? 4 :
str_cmp(str, "May"sv) ? 5 :
str_cmp(str, "Jun"sv) ? 6 :
str_cmp(str, "Jul"sv) ? 7 :
str_cmp(str, "Aug"sv) ? 8 :
str_cmp(str, "Set"sv) ? 9 :
str_cmp(str, "Oct"sv) ? 10 :
str_cmp(str, "Nov"sv) ? 11 :
str_cmp(str, "Dec"sv) ? 12 :
throw "Compile-time error: Not a month!";
}
CONSTEXPR unsigned total(const std::string_view& str)
{
return (str.size() == 11 && str[3] == ' ' && str[6] == ' ') ?
stoi(str.substr(7, 4)) * 512 + month(str.substr(0, 3)) * 32 + stoi(str.substr(4, 2))
: throw "invalid string";
}
}
#define TODO(DATE, MESSAGE)
static_assert(::private_TODO::total(std::string_view(__DATE__, 11)) < ::private_TODO::total(DATE ## sv), MESSAGE)
constexpr
必须在有限数量的递归后求值。您的职能
constexpr bool str_cmp(const char* str, const char* str2, unsigned sz)
{
return sz != 0 ?
*str == *str2 ? str_cmp(str + 1, str2 + 1, sz--)
: false
: true;
}
constexpr unsigned str_size(const char* str, unsigned value = 0)
{
return *str != 0 ?
str_size(str++, value++)
: value;
}
不要。相反,它们构成了无限递归和越界访问。关键是返回值,即传递给递归的值,
sz--
str++
value++
与输入相同。正确的是
constexpr bool str_cmp(const char* str1, const char* str2, unsigned size)
{
return size==0 || (*str1 == *str2 && str_cmp(++str1,++str2,--size));
}
constexpr unsigned str_size(const char* str, unsigned value = 0)
{
return *str? str_size(++str,++value) : value;
}
不过,这可能不是代码中唯一的错误。
相关文章:
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 多成员Constexpr结构初始化
- 条件constexpr函数
- constexpr 函数中的非文字(通过 std::is_constant_evaluated)
- Visual C++ constexpr Hints
- 如何确认我的constexpr表达式实际上已经在编译时执行
- 为什么constexpr的性能比正常表达式差
- 是否可以使用if constexpr删除控制流语句
- 要与"if constexpr"一起使用的编译时消息(在预处理器之后)
- 为什么std::isnan 不是 constexpr?
- Constexpr替代了新的放置方式,可以让内存中的对象保持未初始化状态
- 当一个值是非常量但用常量表达式初始化时使用constexpr
- 更多constexpr容器是否需要mark_immutable_if_consexpr
- C++从其他 constexpr 创建 lambda 不能按顺序执行 Constexpr
- constexpr上下文中std::initializer_list的验证
- constexpr构造函数需要常量成员函数时出现问题
- vs 2015 constexpr变量不恒定,但与2019相比还好吗
- C++constexpr实现差异
- 添加静态constexpr成员是否会更改结构/类的内存映射
- TODO reminder constexpr