将传递的参数限制为非临时字符串文本

Restrict passed parameter to a non-temporary string literal

本文关键字:字符串 文本 参数      更新时间:2023-10-16

对于类似的SO问题,我想出了以下解决方案:

#include <cstdlib>
class Literal
{
  public:
    template <std::size_t N> constexpr
    Literal(const char (&str)[N])
    : mStr(str),
      mLength(checkForTrailingZeroAndGetLength(str[N - 1], N))
    {
    }
    template <std::size_t N> Literal(char (&str)[N]) = delete;
    constexpr operator const char*() const noexcept
    {
        return mStr;
    }
    constexpr const char* c_str() const noexcept
    {
        return mStr;
    }
  private:
    const char* mStr;
    std::size_t mLength;
    struct Not_a_CString_Exception{};
    constexpr static
    std::size_t checkForTrailingZeroAndGetLength(char ch, std::size_t sz)
    {
      return (ch) ? throw Not_a_CString_Exception() : (sz - 1);
    }
};

它运行良好,但仍然可以从具有自动存储持续时间的数组中创建文本。 我想在编译时防止。以下示例具有未定义的行为:

#include <cstdio>
static Literal okay()
{
    static constexpr const char okay[] = "okay";
    return { okay };
}
static Literal boom()
{
    const char boom[] = "boom"; //Oops, static forgotten
    return { boom }; // <= How to force a compile error here?
}
int main()
{
    printf("%sn", okay().c_str()); // <= the intended use case
    printf("%sn", boom().c_str()); // <= the undefined behaviour
    return 0;
}

它也可以在godbolt编译器资源管理器中找到。是否可以在编译时检测到此用例并强制编译错误?

不,这是不可能的。 okayboom 和相同大小的字符串文本都具有相同的类型,并且不能作为表达式区分。