将字符串存储在 constexpr 结构中
store a string in a constexpr struct
是否可以将字符串存储在 constexpr
结构中:
到目前为止我只能想出:
struct A
{
constexpr A(std::string_view n): m_name(n) {}
constexpr auto name(){ return m_name; }
std::string_view m_name; // This might become dangling!!
}
如果这个 class 仅 像这样使用
,这很明显是个好主意
A a = {"Hello"};
constexpr A b = {"World"};
而不是这样
auto makeA(std::string n) { return A{n}; }
A a = makeA("Hello"); // Dangling internal std::string_view
我需要 constexpr
在编译时构造结构。
是否有可能在 运行 时间使它更安全,因为使用 std::string_view
,它不是。
这实际上不是安全问题,而是语义问题。没有什么能阻止你在编译时做完全相同的事情:
constexpr A blub()
{
char str[] = "asdf";
return { str };
}
由于无法在核心常量表达式中调用此函数,因此包含此类代码的程序格式错误,不需要诊断 [dcl.constexpr]/5,这实际上并不比在运行时调用未定义的行为…
编译时与否,你必须问自己这个问题:这个结构应该 own 一个字符串还是 refer 一个现有的字符串?我强烈建议不要让你的结构在运行时上下文中拥有一个字符串并在编译时上下文中引用一个现有的字符串,即使你在理论上找到了一种方法来实现这一点。我们在这里谈论完全不同的语义。完全不同的语义通常应该更好地由不同的类型建模,而不是完全根据上下文改变其含义的一种类型......
如果你想让一个 constexpr 结构拥有一个字符串,你目前必须求助于一些 constexpr 字符串实现,例如 this one. Since your question is tagged with c++20, note that std::string
will be useable in a constexpr context starting with C++20 [basic.string]。因此,在 C++20 中,您可以让成员成为 std::string
…
你可能会:
template<typename Char, Char... Cs>
struct CharSeq
{
static constexpr const Char s[] = {Cs..., 0}; // The unique address
};
// That template uses the extension
template<typename Char, Char... Cs>
constexpr CharSeq<Char, Cs...> operator"" _cs() {
return {};
}
如果您不能使用扩展,请参阅我在 的回答以获得 MAKE_STRING
宏(确实更冗长,并且对可接受的字符串长度进行了硬编码限制)。
然后
struct A
{
template <char ... Cs>
constexpr A(CharSeq<char, Cs...>) : m_name(CharSeq<char, Cs...>::s) {}
constexpr auto name(){ return m_name; }
std::string_view m_name;
};
只有类似于以下的有效用法:
A a = {"Hello"_cs};
constexpr A b = {"World"_cs};
是否可以将字符串存储在 constexpr
结构中:
到目前为止我只能想出:
struct A
{
constexpr A(std::string_view n): m_name(n) {}
constexpr auto name(){ return m_name; }
std::string_view m_name; // This might become dangling!!
}
如果这个 class 仅 像这样使用
,这很明显是个好主意A a = {"Hello"};
constexpr A b = {"World"};
而不是这样
auto makeA(std::string n) { return A{n}; }
A a = makeA("Hello"); // Dangling internal std::string_view
我需要 constexpr
在编译时构造结构。
是否有可能在 运行 时间使它更安全,因为使用 std::string_view
,它不是。
这实际上不是安全问题,而是语义问题。没有什么能阻止你在编译时做完全相同的事情:
constexpr A blub()
{
char str[] = "asdf";
return { str };
}
由于无法在核心常量表达式中调用此函数,因此包含此类代码的程序格式错误,不需要诊断 [dcl.constexpr]/5,这实际上并不比在运行时调用未定义的行为…
编译时与否,你必须问自己这个问题:这个结构应该 own 一个字符串还是 refer 一个现有的字符串?我强烈建议不要让你的结构在运行时上下文中拥有一个字符串并在编译时上下文中引用一个现有的字符串,即使你在理论上找到了一种方法来实现这一点。我们在这里谈论完全不同的语义。完全不同的语义通常应该更好地由不同的类型建模,而不是完全根据上下文改变其含义的一种类型......
如果你想让一个 constexpr 结构拥有一个字符串,你目前必须求助于一些 constexpr 字符串实现,例如 this one. Since your question is tagged with c++20, note that std::string
will be useable in a constexpr context starting with C++20 [basic.string]。因此,在 C++20 中,您可以让成员成为 std::string
…
你可能会:
template<typename Char, Char... Cs>
struct CharSeq
{
static constexpr const Char s[] = {Cs..., 0}; // The unique address
};
// That template uses the extension
template<typename Char, Char... Cs>
constexpr CharSeq<Char, Cs...> operator"" _cs() {
return {};
}
如果您不能使用扩展,请参阅我在 MAKE_STRING
宏(确实更冗长,并且对可接受的字符串长度进行了硬编码限制)。
然后
struct A
{
template <char ... Cs>
constexpr A(CharSeq<char, Cs...>) : m_name(CharSeq<char, Cs...>::s) {}
constexpr auto name(){ return m_name; }
std::string_view m_name;
};
只有类似于以下的有效用法:
A a = {"Hello"_cs};
constexpr A b = {"World"_cs};