I am writing a simple fixed length string struct. In runtime, if you assign strings that are too long, I will just silently truncate them. This is for embedded and the string are to be displayed on a display of limited size, so they would get cropped one way or another.
I thought that it would be neat though, to fail compilation if one tries to assign too long string in compile time. By that I mean calling either of these:
fixed_str str = "bla bla";
fixed_str str2 {"bla bla"};
// and possibly also
fixed_str str3 = std::string_view{"bla bla"};
fixed_str str3 {std::string_view{"bla bla"}};
So the idea was something like this:
template<size_t length>
struct fixed_str final
{
constexpr static auto max_length = length;
static constexpr const char zero_char = 0;
constexpr fixed_str()
{
chars[0] = 0;
}
constexpr fixed_str(const char* str)
{
this->operator=(str);
}
fixed_str& operator=(const char* str)
{
if (str)
{
auto len = std::char_traits<char>::length(str);
auto real_len = std::min(len, length);
if (std::is_constant_evaluated())
{
static_assert(len <= length, "Cannot fit the string into static buffer");
for (size_t i = 0; i < real_len; ++i)
{
chars[i] = str[i];
}
}
else
{
memcpy(chars.data(), str, real_len);
}
chars[real_len] = 0;
}
else
{
chars[0] = 0;
}
return *this;
}
std::array<char, length + 1> chars;
constexpr operator std::string_view() const
{
return { chars.data() };
}
}
However, it is not possible to use function argument or anything derived from it as a static_assert
argument it seems. This would still fail even if I marked the overload consteval
meaning it would only execute at compile time.
I was wondering if there is a way around that without macros. I did find this macro [in another answer][1]:
#include <assert.h>
#include <type_traits>
#define constexpr_assert(expression) do{if(std::is_constant_evaluated()){if(!(expression))throw 1;}else{assert(!!(expression));}}while(0)
However I dislike macros since they cannot be wrapped in namespaces and can conflict with other definitions, especially if copied from stackoverflow. Is there a trick that uses C++ directly?
I tried a few things with making a consteval
function that tries to convert the argument to constant expression but I got the same errors.
[1]: https://stackoverflow.com/a/76370540/607407