C++ 中是否可以强制执行字符串文字函数参数?

par*_*par 10 c++ arguments parameter-passing string-literals

我想知道在 C++ 中是否可以声明一个必须是字符串文字的函数参数?我的目标是接收一个对象,我只能保留指向它的指针,并且知道它不会free()从我下面被删除(即具有应用程序生命周期范围)。

例如,假设我有类似的东西:

#include <string.h>

struct Example {
    Example(const char *s) : string(s) { }

    const char *string;
};

void f() {
    char *freeableFoo = strdup("foo");

    Example e(freeableFoo);     // e.string's lifetime is unknown
    Example e1("literalFoo");   // e1.string is always valid

    free(freeableFoo);

    // e.string is now invalid
}
Run Code Online (Sandbox Code Playgroud)

如示例所示,当ed 时,该freeableFoo成员变得无效。这一切都是在你没有意识到的情况下发生的。free()e.stringExample

显然,如果在其构造函数中复制字符串,我们可以解决这个问题Example,但我不想为副本分配内存。

的构造函数是否可以Example声明“您必须传递字符串文字”(在编译时强制执行),以便知道Example它不必复制字符串并且知道其string指针在应用程序的生命周期内有效?

Bee*_*ope 5

在 C++20 中,您可以使用一个包装类来完成此操作,consteval该类具有一个接受字符串文字的转换构造函数:

struct literal_wrapper
{
    template<class T, std::size_t N, std::enable_if_t<std::is_same_v<T, const char>>...>
    consteval literal_wrapper(T (&s)[N]) : p(s) {}

    char const* p;
};
Run Code Online (Sandbox Code Playgroud)

这个想法是字符串文字具有类型const char[N]并且我们匹配它。

然后,您可以在想要强制传递字符串文字的地方使用此包装类:

void takes_literal(string_literal lit) {
  // use lit.p here
}
Run Code Online (Sandbox Code Playgroud)

您可以将其称为foo("foobar").

请注意,这也将匹配静态存储const char[]数组,如下所示:

const char array[] = {'a'};


takes_literal(array); // this compiles
Run Code Online (Sandbox Code Playgroud)

然而,静态数组具有与字符串文字大部分相同的特征,例如无限的存储持续时间,这可能适合您。

它与本地数组不匹配,因为衰减的指针值不是常量表达式(这就是consteval出现的地方)。

这个答案几乎直接复制自 CM对问题的评论中建议的第一个变体。


Dam*_*hev 0

只需让构造函数显式采用右值即可:

struct Example {
   Example(const char*&& s) : string(s) { }

   const char* string;
};
Run Code Online (Sandbox Code Playgroud)