For a similar SO question I came up with the following solution:
#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);
}
};
It works very well, but it is still possible to create a Literal from arrays with automatic storage duration. which I would like to prevent at compile time. The following example has undefined behaviour:
#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;
}
It can also be found at godbolt compiler explorer. Is it possible to detect this use case at compile time and force an compile error?