我想最好的做法是使用
const char (&s)[N]
(带有
template<size_t N>
) 作为参数类型。不过它也会绑定到除字符串字面值外的任何 const char 数组上。
添加一个被删除的非 const char 数组构造函数,以禁止使用非 const 数组调用它。
class LitRf
{
const char* data_;
Sz size_;
public:
template<size_t N>
LitRf(char const (&s)[N])
: data_{s}, size_{N}
{}
template<size_t N>
LitRf(char (&s)[N]) = delete;
};
除此之外,您可以使用宏包装器,这样(当构造函数从未在没有它的情况下使用时)只能通过文字构造对象,甚至不能通过变量构造。
这个想法是将两个字符串字面值连接在一起,其中第二个字符串只是一个空字符串。只有第一个也是字符串字面值时才有可能实现这一点;如果放置一个变量,那么就会出现语法错误。经过宏展开后,编译器看到类似于LitRf("foo" "")
的东西,它等同于LitRf("foo")
。以下是一些例子:
auto x = MakeLitRf("foo"); // works
const char *foo = "foo";
auto x = MakeLitRf(foo); // fails
auto x = LitRf(foo); // works, but we want it to fail...
在最后一种情况下,用户无意中(或有意?)没有使用宏,使我们的工作变得毫无价值。为了让其也失败,可以向构造函数添加一个隐藏参数,该参数在直接调用时需要添加(当然,在宏的定义中也要添加)。
class LitRf
{
const char* data_;
Sz size_;
public:
LitRf(const char *s, void *)
: data_{s}, size_{N}
{}
LitRf(const char *s)
{
static_assert(false, "Please use the macro `MakeLitRf` with a string literal to construct a `LitRf`.");
}
};
#define MakeLitRf(s) LitRf(s "", nullptr)
const char (&s)[N]
(带有template<size_t N>
)作为参数类型。但它也绑定到除字符串字面值之外的任何const char数组。 - leemes=delete
它。 - leemessizeof(s)
吗?因为在你的情况下,这将返回1... 你可能想要使用strlen(s)
或者如果s
是一个数组,则使用sizeof(s) - 1
。即使在那种情况下,也不要使用sizeof(s)
。请注意,字符串结束符零包含在数组大小中,但不包括在字符串大小(strlen)中。 - leemessizeof
通常是4(32位架构,CHAR_BIT == 8)或8(64位架构)用于指针,或者用于文字或数组的存储大小(包括终止0)。 我的意思是让我的size_
存储存储大小(与您的答案完全相同),但从大小中减去或不减去1与问题关系不大。;-) - Petr Skocik