compile-time variable-length objects 基于字符串
compile-time variable-length objects based on string
相关的 SO 问题:
遗憾的是,没有一个(或其他类似的)提供我正在寻找的解决方案。
背景
USB 描述符(通常)是 byte-array 结构。 “字符串描述符”定义为字节数组,以 2 个字节的标准“header”开头,后跟一串 UNICODE(16 位)字符。
例如,值为“AB”的 USB 字符串描述符将具有以下字节序列:
0x06 0x03 0x41 0x00 0x42 0x00
其中0x06
是描述符的总大小(包括header),0x03
是它的“类型”(由标准定义)
当前(不满意)方法:
// other types omitted for clarity
enum UsbDescriptorType: uint8_t { USB_DESCR_STRING = 0x03 };
struct UsbDescrStd {
uint8_t bLength;
UsbDescriptorType bDescriptorType;
};
template<size_t N>
struct UsbDescrString final: UsbDescrStd {
char str[N * 2];
constexpr UsbDescrString(const char s[N]) noexcept
: UsbDescrStd{sizeof(*this), UsbDescriptorType::USB_DESCR_STRING}
, str {}
{
for(size_t i = 0; i < N; ++i)
str[i * 2] = s[i];
}
};
下面是它的用法示例,以及为什么它们对我来说“不够好”的简短评论:
// requires size information
constexpr UsbDescrString<9> uds9{"Descr str"};
// string duplication
constexpr UsbDescrString<sizeof("Descr str")-1> udsa{"Descr str"};
// requires an explicit string storage
constexpr auto UsbDescrStrTxt{"Descr str"};
constexpr UsbDescrString<sizeof(UsbDescrStrTxt)-1> udsa2{UsbDescrStrTxt};
// ugly use of a macro
#define MAKE_UDS(name, s) UsbDescrString<sizeof(s)-1> name{s}
constexpr MAKE_UDS(udsm, "Descr str");
从 C++20 开始,“模板的字符串参数”被明确禁止,也切断了该解决方案。
我想要达到的目标
理想情况下,我希望能够编写如下代码:
constexpr UsbDescrString uds{"Descr str"}; // or a similar "terse" approach
它简单、简洁,error-resistant,而且切中要点。我需要帮助以一种允许我创建 compile-time objects 而没有不必要的代码膨胀的方式编写 UsbDescrString
。
在 UsbDescrString
中添加一个 CTAD 就足够了
template<size_t N>
struct UsbDescrString final: UsbDescrStd {
char str[N * 2];
constexpr UsbDescrString(const char (&s)[N+1]) noexcept
: UsbDescrStd{sizeof(*this), UsbDescriptorType::USB_DESCR_STRING}
, str {}
{
for(size_t i = 0; i < N; ++i)
str[i * 2] = s[i];
}
};
template<size_t N>
UsbDescrString(const char (&)[N]) -> UsbDescrString<N-1>;
注意,为了防止数组到指针衰减,需要使用const char (&)
作为构造函数参数。
"String argument to template" is explicitly prohibited as of C++20,
cutting that solution off as well.
但是,多亏了 P0732,借助一些帮助程序 类,例如 basic_fixed_string
,现在在 C++20 中您可以
template<fixed_string>
struct UsbDescrString final: UsbDescrStd;
constexpr UsbDescrString<"Descr str"> uds9;
相关的 SO 问题:
遗憾的是,没有一个(或其他类似的)提供我正在寻找的解决方案。
背景
USB 描述符(通常)是 byte-array 结构。 “字符串描述符”定义为字节数组,以 2 个字节的标准“header”开头,后跟一串 UNICODE(16 位)字符。
例如,值为“AB”的 USB 字符串描述符将具有以下字节序列:
0x06 0x03 0x41 0x00 0x42 0x00
其中0x06
是描述符的总大小(包括header),0x03
是它的“类型”(由标准定义)
当前(不满意)方法:
// other types omitted for clarity
enum UsbDescriptorType: uint8_t { USB_DESCR_STRING = 0x03 };
struct UsbDescrStd {
uint8_t bLength;
UsbDescriptorType bDescriptorType;
};
template<size_t N>
struct UsbDescrString final: UsbDescrStd {
char str[N * 2];
constexpr UsbDescrString(const char s[N]) noexcept
: UsbDescrStd{sizeof(*this), UsbDescriptorType::USB_DESCR_STRING}
, str {}
{
for(size_t i = 0; i < N; ++i)
str[i * 2] = s[i];
}
};
下面是它的用法示例,以及为什么它们对我来说“不够好”的简短评论:
// requires size information
constexpr UsbDescrString<9> uds9{"Descr str"};
// string duplication
constexpr UsbDescrString<sizeof("Descr str")-1> udsa{"Descr str"};
// requires an explicit string storage
constexpr auto UsbDescrStrTxt{"Descr str"};
constexpr UsbDescrString<sizeof(UsbDescrStrTxt)-1> udsa2{UsbDescrStrTxt};
// ugly use of a macro
#define MAKE_UDS(name, s) UsbDescrString<sizeof(s)-1> name{s}
constexpr MAKE_UDS(udsm, "Descr str");
从 C++20 开始,“模板的字符串参数”被明确禁止,也切断了该解决方案。
我想要达到的目标
理想情况下,我希望能够编写如下代码:
constexpr UsbDescrString uds{"Descr str"}; // or a similar "terse" approach
它简单、简洁,error-resistant,而且切中要点。我需要帮助以一种允许我创建 compile-time objects 而没有不必要的代码膨胀的方式编写 UsbDescrString
。
在 UsbDescrString
中添加一个 CTAD 就足够了
template<size_t N>
struct UsbDescrString final: UsbDescrStd {
char str[N * 2];
constexpr UsbDescrString(const char (&s)[N+1]) noexcept
: UsbDescrStd{sizeof(*this), UsbDescriptorType::USB_DESCR_STRING}
, str {}
{
for(size_t i = 0; i < N; ++i)
str[i * 2] = s[i];
}
};
template<size_t N>
UsbDescrString(const char (&)[N]) -> UsbDescrString<N-1>;
注意,为了防止数组到指针衰减,需要使用const char (&)
作为构造函数参数。
"String argument to template" is explicitly prohibited as of C++20, cutting that solution off as well.
但是,多亏了 P0732,借助一些帮助程序 类,例如 basic_fixed_string
,现在在 C++20 中您可以
template<fixed_string>
struct UsbDescrString final: UsbDescrStd;
constexpr UsbDescrString<"Descr str"> uds9;