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

时间:2017-06-22 08:36:33

标签: c++ c++11 c++14

对于a similar SO question,我想出了以下解决方案:

#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);
    }
};

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

#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("%s\n", okay().c_str()); // <= the intended use case
    printf("%s\n", boom().c_str()); // <= the undefined behaviour
    return 0;
}

也可以在godbolt compiler explorer找到它。是否有可能在编译时检测到这个用例并强制编译错误?

1 个答案:

答案 0 :(得分:0)

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