首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用户为std::integral_constant定义的文字

用户为std::integral_constant定义的文字
EN

Code Review用户
提问于 2014-05-16 13:10:07
回答 1查看 2.5K关注 0票数 12

我创建了一个用户定义的文本_c,以将“整数”文本转换为std::integral_constant。基本上,目标是允许用户编写std::integral_constant实例而不使用通常的样板。以下是实现:

代码语言:javascript
复制
#include <type_traits>

template<typename T, typename U>
constexpr auto pow_helper(T acc, T value, U times)
    -> T
{
    return (times > 1) ?
        pow_helper(acc*value, value, times-1) :
            acc;
}

// Compile-time pow function, only works with
// an unsigned integer exponent
template<typename T, typename U>
constexpr auto pow(T value, U exponent)
    -> T
{
    return (exponent == 0) ? 1 :
        (exponent > 0) ? pow_helper(value, value, exponent) :
            1 / pow_helper(value, value, -exponent);
}

// Structure to parse an integer literal
template<typename Integral, char C, char... Digits>
struct parse
{
    static constexpr Integral value =
        parse<Integral, C>::value * pow(10u, sizeof...(Digits))
        + parse<Integral, Digits...>::value;
};

// Specialization of parse to parse a single
// decimal digit
template<typename Integral, char C>
struct parse<Integral, C>
{
    static_assert(C >= '0' && C <= '9',
                  "only characters in range 0..9 are accepted");

    static constexpr Integral value = C - '0';
};

// User defined literal for std::integral_constant
template<char... Digits>
constexpr auto operator"" _c()
    -> std::integral_constant<int, parse<int, Digits...>::value>
{
    return {};
}

使用这个文本,wirting 42_c生成一个std::integral_constant<int, 42>实例。下面是一个小的工作示例:

代码语言:javascript
复制
int main()
{
    std::cout << 45_c << '\n';   // prints 45
    std::cout << -23_c << '\n';  // prints -23

    static_assert(std::is_same<decltype(58_c), std::integral_constant<int, 58>>::value, "");
}

为了生成其他积分常量,我计划添加用户定义的文本_cl_cll_cu_cul_cull whoe实现完全相同,只有结果类型不同。

是否有办法改进这段代码并/或使其更简洁或更地道?我错过了一些潜在的缺陷吗?

EN

回答 1

Code Review用户

回答已采纳

发布于 2014-05-23 19:43:21

使用"fat“模板

我会尽量避免在有别名模板或constexpr函数的优雅的替代解决方案时使用成熟的类模板。请注意,我没有度量这一点,因此,可以使用少量的盐分:轻量级的constexpr函数和别名模板可以更快地实例化。使用constexpr函数可以将实例化的数量减少到至少1(文字操作符模板)或两个(具有单个模板类型参数的constexpr函数模板)。

算法

通过更改操作顺序,您可以完全摆脱pow函数(模板):将当前结果传递到下一步,然后乘并添加。换挡(在基地10)将在飞行中进行。

素描:

代码语言:javascript
复制
constexpr int combine(int p)
{
    return p;
}

template<class... TT>
constexpr int combine(int val, int p0, TT... pp)
{
    return combine(val*10 + p0, pp...);
}

constexpr int parse(char C)
{
    return (C >= '0' && C <= '9')
           ? C - '0'
           : throw std::out_of_range("only decimal digits are allowed");
}

template<char... Digits>
constexpr auto operator"" _c()
-> std::integral_constant<int, combine(0, parse(Digits)...)>
{
    return {};
}

在其他碱基中的文字

您的解析函数目前拒绝十六进制、八进制和C++1y二进制文本,以及C++1Y的数字分隔符。支持基数< 10是相当简单的,因为你只需要改变“移动”因素。即乘以8或2,而不是10。对于基数16,还需要在字符->数字转换中添加一些代码。IIRC,不能保证这些字母在基本执行字符集(相对于数字)中是连续的,因此这可能是相当痛苦的切换或查找表。此外,上/下大小写。

自动增长文字类型

正常的C++文本会根据其值自动调整其类型。如果他们不适合一个int,他们会尝试longlong long等。也许其中一个用户定义的文字应该模仿这种行为,以方便。

算子

不幸的是,StdLib没有为std::integral_constant提供运算符。因此,-23_c将不是std::integral_constant<int, -23>,而是int (通过隐式转换运算符)。我觉得很奇怪。

考虑使用自定义类型,可能从/可转换到std::integral_constant,并为这种类型提供(元编程)运算符。

旁注:

lit<45>更容易实现:

代码语言:javascript
复制
template<std::uintmax_t N>
using lit = std::integral_constant<std::uintmax_t, N>;
票数 9
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/50910

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档