首页 > 解决方案 > 显式(布尔)可以作用于字符文字参数的长度吗?

问题描述

我正在编写一个自定义字符串类,它有利于空间效率高于几乎任何其他考虑因素。它对 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();
}

标签: c++language-lawyerc++20

解决方案


这是一个简短的复制:

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 91429llvm 42980


推荐阅读