9

我一直在研究 C++11 的一些新特性,其中一些特性给我留下了深刻的印象,尤其是用户定义的文字。

这些允许您定义形式的文字,999_something其中控制对生成文字something所做的操作。999所以不再需要使用:

#define MEG * 1024 * 1024
int ten_meg = 10 M;

我认为这会很好地实现大量下划线,就像1_000_000_blahPerl 的可读性一样,尽管 Perl 以某种方式可读的想法对我来说似乎很幽默 :-)

1101_1110_b对于像和这样的二进制值也很方便0011_0011_1100_1111_b

显然,由于_字符的原因,这些将需要是原始模式类型,处理 C 字符串,我可以接受。

知道如何根据操作数大小提供不同的类型。例如:

1101_1110_b

应该给出一个char(当然假设char是 8 位),而:

0011_0011_1100_1111_b

将提供 16 位类型。

我可以从文字运算符函数operator""本身(通过计算数字字符)中获取操作数的长度,但返回类型似乎固定在函数中,所以我不能基于此返回不同的类型。

这可以通过_b用户定义类型框架中的单个后缀来完成,还是我需要求助于手动拆分类型(_b8等等_b16)并提供大部分重复的功能?

4

2 回答 2

6

你需要知道你的字符串的大小,实现这一点的唯一方法是使用一个参数包sizeof...。您应该能够使用可变参数模板实现您想要的operator""

#include <cstdint>
#include <type_traits>

template<char... String>
auto operator "" _b()
    -> typename std::conditional<sizeof...(String) <= 8,
        uint8_t,
        typename std::conditional<sizeof...(String) <= 16,
            uint16_t,
            uint32_t
        >::type
    >::type
{
    // Do whatever you want here
}

这是一个测试用例:

int main()
{
    auto a = 10000001_b;
    auto b = 100000001_b;

    std::cout << std::boolalpha;
    std::cout << std::is_same<decltype(a), uint8_t>::value << "\n"; // true
    std::cout << std::is_same<decltype(b), uint16_t>::value << "\n"; // true
}

不幸的是,该解决方案无法处理数字分隔符。此外,std::conditional机器相当丑陋。您可能可以更好地使用boost::mpl::vector,boost::mpl::at和一些算术运算。

于 2013-06-21T07:18:36.173 回答
0

感谢Morwenn 的回答,我为我们这些坚持使用 C++11 的人提出了用户定义二进制文字的完整解决方案:

#include <cstdint>
#include <type_traits>

/// User-defined binary literal for C++11
/// @see https://stackoverflow.com/a/538101 / https://gist.github.com/lichray/4153963
/// @see https://stackoverflow.com/a/17229703
namespace detail {

template<class tValueType, char... digits>
struct binary_literal;

template<char... digits>
struct unsigned_binary_literal
{
    using Type = typename std::conditional<sizeof...(digits) <= 8, uint8_t,
                    typename std::conditional<sizeof...(digits) <= 16, uint16_t,
                        typename std::conditional<sizeof...(digits) <= 32, uint32_t, uint64_t>::type
                    >::type
                >::type;
};

template<char... digits>
struct signed_binary_literal
{
    using Type = typename std::conditional<sizeof...(digits) <= 8, int8_t,
                    typename std::conditional<sizeof...(digits) <= 16, int16_t,
                        typename std::conditional<sizeof...(digits) <= 32, int32_t, int64_t>::type
                    >::type
                >::type;
};

template<class tValueType, char high, char... digits>
struct binary_literal<tValueType, high, digits...>
{
    static constexpr tValueType value = (static_cast<tValueType>(high == '1') << (sizeof...(digits))) ^ binary_literal<tValueType, digits...>::value;
};

template<class tValueType, char high>
struct binary_literal<tValueType, high>
{
    static constexpr tValueType value = (high == '1');
};
} // namespace detail

/// C++11 support for binary literal
/// @tparam digits to transform to an unsigned integer
template<char... digits>
constexpr auto operator "" _bin() -> typename detail::unsigned_binary_literal<digits...>::Type
{
    return detail::binary_literal<typename detail::unsigned_binary_literal<digits...>::Type, digits...>::value;
}

/// C++11 support for binary literal
/// @tparam digits to transform to a signed integer
template<char... digits>
constexpr auto operator "" _sbin() -> typename detail::signed_binary_literal<digits...>::Type
{
    return static_cast<typename detail::signed_binary_literal<digits...>::Type>(detail::binary_literal<typename detail::unsigned_binary_literal<digits...>::Type, digits...>::value);
}
于 2018-12-10T09:23:20.597 回答