c++ - 显式(布尔)可以作用于字符文字参数的长度吗?
问题描述
我正在编写一个自定义字符串类,它有利于空间效率高于几乎任何其他考虑因素。它对 6 个字符或更少字符的字符串进行了小字符串优化,并对任何更大的字符串使用实习。下面包含一个稍微精简的版本(编译器资源管理器)。
为方便起见,我想从字符串文字转换构造函数,仅当字符串文字足够短以适合 sso 缓冲区时才隐式使用。对于更长的字符串,我希望构造函数是明确的,以防止它被意外使用(因为实习的性能影响)。
在下面的代码中,我预计初始化Str b = "not so short"
会导致编译器错误,因为条件显式说明符表达式为真。但是,我在三个主要编译器中的任何一个上都没有收到错误。注意:Str a = "short"
初始化工作正常。
至少有一个“编译器”认为这应该像我预期的那样工作:Visual Studio 的 Intellisense 功能使用的 EDG 前端给了我一个带有错误的红色曲线no suitable constructor exists to convert from "const char[13]" to "Str"
。
class Str final {
public:
using value_type = char;
using pointer = value_type const*;
using size_type = unsigned long long;
// maximum length of a sso string
static auto constexpr ssoMaxLen = sizeof(pointer) - 2;
// construct from a character literal
template <size_type N>
explicit(N > ssoMaxLen + 1) Str(char const (&str)[N]);
// construct from a zero-terminated string (other than a literal)
explicit Str(pointer&& rstr);
size_type size() const noexcept;
private:
// the only non-static data is in this union
union {
size_type integral;
pointer ptr;
value_type text[sizeof(pointer)];
};
// index of the sso data and size in the text member when using sso
// this assumes little endian
static auto constexpr ssoData = 1;
static auto constexpr ssoSize = 0;
// masks for the different parts of the instance data
static auto constexpr ssoSizeMask = sizeof(pointer) - 1;
static auto constexpr ssoDataMask = ~ssoSizeMask;
// perform interning of long strings
static pointer InitLong(pointer str, size_type len);
};
template <Str::size_type N>
Str::Str(char const(&str)[N]) {
// construct an empty string and return if length is 0
auto const len = N - 1;
if (len == 0) {
ptr = nullptr;
return;
}
// do interning and return if length is long enough
if (len > ssoMaxLen) {
ptr = InitLong(str, len);
return;
}
// otherwise intinialize in sso mode
text[ssoSize] = len;
text[ssoData + 0] = str[0];
text[ssoData + 1] = len > 1? str[1] : 0;
text[ssoData + 2] = len > 2? str[2] : 0;
if constexpr (ssoMaxLen >= 3) text[ssoData + 3] = len > 3? str[3] : 0;
if constexpr (ssoMaxLen >= 4) text[ssoData + 4] = len > 4? str[4] : 0;
if constexpr (ssoMaxLen >= 5) text[ssoData + 5] = len > 5? str[5] : 0;
if constexpr (ssoMaxLen >= 6) text[ssoData + 6] = 0;
}
int main() {
Str a = "short";
Str b = "not so short";
return a.size() + b.size();
}
解决方案
这是一个简短的复制:
using size_t = decltype(sizeof(0));
struct Str {
template <size_t N>
explicit(N > 7) Str(char const (&str)[N]);
};
#ifdef OUT_OF_LINE
template <size_t N>
Str::Str(char const(&str)[N]) { }
#endif
Str a = "short";
Str b = "not so short";
照原样,gcc 和 clang 都正确拒绝。如果您定义OUT_OF_LINE
,则两个编译器都接受。归档gcc 91429和llvm 42980。
推荐阅读
- go - 单一方法上的多个接收器
- python - 保存后“OSError:无法将文件解释为泡菜”
- java - 寻找回文数
- hadoop - 高可用性在 Hadoop 集群中不起作用
- powershell-7.0 - New-AzureADApplication RequiredResourceAccess
- javascript - 单击按钮发送 HTTP 请求时防止 HTML 页面重新加载 [更新]
- java - Android Studio 记住播放器进度
- node.js - 使用 MongoDB 和 Graphql 管理聊天室中的消息
- c++ - 通过二进制和
和十六进制 - arduino - 如何对自己的 Wifi“静音”单块播放器进行编程以远程控制 Behringer X32 机架?