User-Defined Literals 介绍
  ZXL8ALkrtBPG 2023年12月06日 23 0

自C++11起支持用户自定义字面量,用户定义字面量有如下:

User-Defined Literals 介绍_c++

字面量运算符

用户定义字面量所调用的函数被称为字面量运算符 ,形式为:operator ""标识符;

字面量运算符仅允许下列形参列表:

User-Defined Literals 介绍_c++_02

详细说明可以参见【1】;

用户可以自定义字面量进行单位转换或类型转换,例如:

struct mytype
{
    unsigned long long m;
};

constexpr mytype operator""_km(unsigned long long n)
{
    return {n};
}

mytype y = 123_km;

字面量运算符模板

如果字面量运算符是模板,那么它必须有空形参列表,并且只能有一个模板形参,模板形参必须是元素类型是 char 的非类型模板形参包(此时称之为数值字面量运算符模板):

template<char...>
double operator ""_x();

或类类型的非类型模板形参(此时称之为字符串字面量运算符模板):(C++20 起)

struct A { constexpr A(const char*); };
 
template<A a>
A operator ""_a();

这里延伸出如何借用“字面量运算符模板 ”将字符串字面量映射编译期的常量类型,hana库中提供了一种实现:

template<char ...Cs>
struct Str {
    static constexpr bool isEmpty = false;
    static constexpr char value[] = {Cs..., '\0'};
    constexpr operator const char*(){ return value; }
};

template<>
struct Str<> {
    static constexpr bool isEmpty = true;
};

template<typename T, T ...Cs>
constexpr Str<Cs...> operator""_S()
{
    return {};
}

constexpr auto s = "hello world"_S;
using Type = decltype("hello world"_S); // 获取编译期字符串类型

但这种实现是Clang和Gcc的扩展实现【2】:

This form will be used if a non-template literal operator for the string literal is not available. The first template argument will be the element type of the string, and the remaining arguments are the code units in the string literal (excluding its terminating null character).

但此语法糖并非标准,因此会产生告警,在Hana中也进行了说明【3】:

Warning:This user-defined literal is an extension which requires a special string literal operator that is not part of the standard yet. That operator is supported by both Clang and GCC, and several proposals were made for it to enter C++17. However, since it is not standard, it is disabled by default and defining the BOOST_HANA_CONFIG_ENABLE_STRING_UDL config macro is required to get this operator. Hence, if you want to stay safe, just use the BOOST_HANA_STRING macro instead. If you want to be fast and furious (I do), define BOOST_HANA_CONFIG_ENABLE_STRING_UDL.

Hana提供了另外一种实现:

namespace string_detail {
    template <char ...s>
    struct string {
        static constexpr char string_storage[sizeof...(s) + 1] = {s..., '\0'};
    };  

    template <typename S, std::size_t ...N>
    constexpr string<S::get()[N]...>
    prepare_impl(S, std::index_sequence<N...>)
    { return {}; }

    template <typename S>
    constexpr decltype(auto) prepare(S s) {
        return prepare_impl(s,
            std::make_index_sequence<sizeof(S::get()) - 1>{});
    }   
}

#define BOOST_HANA_STRING(s)                                                \
    (::string_detail::prepare([]{                                           \   
        struct tmp {                                                        \
            static constexpr decltype(auto) get() { return s; }             \
        };                                                                  \   
        return tmp{};                                                       \   
    }()))                                                                   \


constexpr auto s = BOOST_HANA_STRING("hello world");
using Type = decltype(BOOST_HANA_STRING("hello world")); // 编译失败,因为不允许在decltype中定义类型

但是却无法使用decltype使用一行代码得到其类型;

C++20添加支持了 class template argument deduction ,即模板参数的类型推导【4】

template<class T>
struct X
{
    constexpr X(T) {}
};
 
template<X x>
struct Y {};
 
Y<0> y; // OK, Y<X<int>(0)>, 可以推导非类型模板参数中的X模板参数为int

在提案【5】提供了参考实现:

template<auto size>
struct FixedString {
  char data[size + 1]{};
  constexpr FixedString(char const* str) { std::copy_n(str, size + 1, data); }
  constexpr operator std::string_view() const { return {data, size}; }
};
template<auto size> FixedString(const char (&)[size]) -> FixedString<size - 1>;

template<FixedString str>
constexpr auto operator""_s() { return str; }

constexpr auto s = "hello world"_S;
using Type = decltype("hello world"_S); // 获取编译期字符串类型

参考资料

【1】https://en.cppreference.com/w/cpp/language/user_literal

【2】https://open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3599.html

【3】http://boostorg.github.io/hana/structboost_1_1hana_1_1string.html#a7f15faa77e126e1c2b08a2224ceefb84

【4】https://en.cppreference.com/w/cpp/language/class_template_argument_deduction#Deduction_for_alias_templates

【5】https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0732r2.pdf

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年12月06日 0

暂无评论

推荐阅读
  gBkHYLY8jvYd   2023年11月19日   27   0   0 #includecic++
  ZXL8ALkrtBPG   2023年11月02日   67   0   0 c++
  ZXL8ALkrtBPG   2023年12月06日   24   0   0 字面量c++
  lh6O4DgR0ZQ8   2023年11月24日   18   0   0 cii++c++
  ZXL8ALkrtBPG   2023年11月12日   30   0   0 c++
  gBkHYLY8jvYd   2023年11月19日   27   0   0 十进制高精度c++
  ZXL8ALkrtBPG   2023年11月02日   52   0   0 c++
  gBkHYLY8jvYd   2023年12月11日   20   0   0 cic++最小值
  gBkHYLY8jvYd   2023年11月19日   25   0   0 测试点cic++
ZXL8ALkrtBPG