想要具有外部链接的字符串文字背后的主要动机是使用字符串文字作为非类型模板参数。
我想象一个具有外部链接的字符串文字具有类似于
的定义前缀中带有 e 的string-literal 是具有外部链接的 string-literal。
template<auto&> struct S{}; void bar() { S<e"foo"> s; }
将具有相当于
的行为template<auto&> struct S{}; constexpr char __foo[] = "foo"; void bar { S<__foo> s; }
有没有理由不使用外部链接字符串文字? 以某种方式添加另一个前缀(如
e"Lorem Ipsum"
)会使字符串文字具有外部链接有害吗?
注意:已经可以实现外部链接字符串,但这是一种糟糕的做事方式。
#include<boost/metaparse/v1/string.hpp>
template<typename>
struct hack;
template<char... Cs>
struct hack<boost::metaparse::v1::string<Cs...>>
{
static constexpr char arr[] = {Cs..., '\0'};
};
#define E(str) hack<BOOST_METAPARSE_STRING(str)>::arr
template<auto&> struct S{};
S<E("I'm an external linkage string")> s; // compiles
Boost 使用 python 脚本来生成
BOOST_METAPARSE_STRING
的实现,这太糟糕了。
由于 非类型模板参数中的 P0732 类类型,这个问题在 C++20 中将变得毫无意义。
非类型模板参数是基本类型和类类型之间不对称的最后痕迹。它的存在不是通过选择,而是出于必然:尚不清楚链接器应该如何处理它们。
链接器需要能够区分两个模板类,为了做到这一点,它需要回答两个对象
a
和 b
是否相等。对于基本类型来说这是微不足道的,但对于类类型来说,使用 C++20 之前可用的工具是无法解决的。
P0515 一致性比较 给出了确定两个类类型对象是否相等的机制,只要它们具有简单的
operator<=>
,它具有成员比较的语义。
如果P0732通过,你就可以写
template<size_t N>
struct fixed_string
{
constexpr fixed_string(const char (&str)[N]) { std::copy(str, str + N, data); }
auto operator<=>(const fixed_string&) const = default;
char data[N];
};
template<size_t N>
fixed_string(const char(&)[N]) -> fixed_string<N>;
template<fixed_string> struct S {};
S<"foo"> s;
另请参阅对文本格式化库的思考,该库也有利于进入 C++20。
仅使用 constexpr 函数就可以解析字符串。 这是一个非常简单的例子:
constexpr int placeholder_count(const char* s, size_t i = 0, int result = 0)
{
return s[i] == 0
? result
: (s[i] == '%')
? placeholder_count(s, i + 1, result + 1)
: placeholder_count(s, i + 1, result);
}
int main()
{
static_assert(placeholder_count("foo %s bar %d") == 2, "");
return 0;
}
https://wandbox.org/permlink/TwN0UALpp0e6qfqr
你可以使用它实现很多实用的东西,特别是如果允许 C++14,则需要更少的递归。
有关更高级的用例,请查看元解析: http://www.boost.org/doc/libs/1_64_0/doc/html/metaparse.html
§ 3.5 程序与联动[basic.link]
- 当一个名称可能表示与一个对象、引用、函数、类型、模板、命名空间或值相同的对象、引用、函数、类型、模板、命名空间或值时,就被认为具有链接 由另一个作用域中的声明引入的名称
正如评论中提到的,只有名称才有联系。字符串文字不是名称。
§ 2.13.5 字符串文字 [lex.string]
- 评估字符串文字会产生具有静态存储持续时间的字符串文字对象,该对象从给定字符初始化为 上面指定的。 所有字符串文字是否不同(即 存储在不重叠的对象中)以及是否连续 字符串文字的计算会产生相同或不同的对象 未指定。
所以实际的问题是具有相同值的不同字符串文字可以存储在不同的对象中。更重要的是,对同一文字的连续求值可能会产生不同的对象。