另一个字符串文字,UDL 迷宫
Posted
技术标签:
【中文标题】另一个字符串文字,UDL 迷宫【英文标题】:Yet another string literal, UDL labyrinth 【发布时间】:2019-08-19 07:10:36 【问题描述】:注意:这是 MSVC,C++17 问题。
免责声明:我知道这已经尝试过了,是的,我试图找到相关的 SO 答案。
我可以编写UDL,以实现在编译时将数字文字转换为std::array
:
// std::array '1','2','3'
constexpr auto a_1 = 123_std_char_array;
// std::array '0','x','1','2'
constexpr auto a_2 = 0x12_std_char_array;
// std::array '4'.'2','.','1','3'
constexpr auto a_3 = 42.13_std_char_array;
这是我制作的 UDL:
template< char ... Chs >
inline constexpr decltype(auto) operator"" _std_char_array( )
// append '\0'
return std::array Chs..., char(0) ;
惊人的,时髦的,现代的,等等,等等,等等……但是。
问题
我如何编写一个 UDL 来实现这一点:
// std::array 'S','t','r','i','n','g'
constexpr auto std_char_array_buff_ =
"String"_std_char_array ;
请在 MSVC 中使用 C++17。
忏悔
我知道要“捕获”字符串文字的 UDL 必须有这个足迹:
inline auto operator"" _X( const char*, size_t);
我知道如何在编译时将字符串文字转换为 std::array。但是没有UDL。 Please see here,求灵感。
是的,我知道 C++20 将添加 UDL 模板,而 GCC、clang 现在还有其他东西。虽然我看不出这对我有什么帮助。
最后,我知道我可以做到:
constexpr auto string_view_ = "String"sv ;
【问题讨论】:
我知道如何在编译时将字符串文字转换为 std::array。但是没有 UDL。 为什么不能直接从 UDL 调用 that?除非您的意思是转换const char[N]
而不是 const char*
和 std::size_t
。
@Zereges,请告诉我们你会如何做到这一点?
@ChefGladiator,Zerege 可能在谈论to_array
是如何实现的,使用const char (&)[N]
参数,推导出模板参数N
,它既不是UDL 的有效参数,也不能从const char*
和 size_t
,即使 size_t
的值在编译时是已知的。
@JoelFilho 没错。这是 code 有趣的 MSVC 失败。
@JoelFilho 是的,我明白 Zereges 在说什么。唉,我有点困惑,这对我们有什么帮助?我相信我们中的许多人使用这种代码已经很长时间了。而且我知道不能像 Zerges 建议的那样以某种方式“从 UDL 调用”。很抱歉直言不讳。
【参考方案1】:
不幸的是,这在 C++17 中似乎是不可能的。 user-defined-string-literal 只能匹配每个 [lex.ext]/5 的 operator""X(str, len)
。那么len
是一个函数参数,函数参数不能转换为模板参数。就像你不能这样做:
template <int N>
struct S ;
constexpr auto f(int n)
return S<n>; // no, n is not guaranteed to be known at compile time
"foo"sv
之所以有效,是因为大小不是std::basic_string_view
的模板参数,而是一个“运行时”属性,它恰好受益于constexpr
。你不能用std::array
来做,因为大小是std::array
的模板参数。
make_array
之所以有效,是因为它不是文字运算符,因此它可以将大小作为 template 参数而不是 function 参数。然后,它可以将模板参数传递给std::array
。文字运算符无法做到这一点。
在 C++20 中,我认为我们可以使用这样的包装器类型:
template <std::size_t N>
struct helper
std::array<char, N> string;
template <std::size_t... Is>
constexpr helper(const char (&str)[N + 1], std::index_sequence<Is...>)
:stringstr[Is]...
constexpr helper(const char (&str)[N + 1])
:helperstr, std::make_index_sequence<N>
;
template <std::size_t N>
helper(const char (&str)[N]) -> helper<N - 1>;
然后使用字符串文字操作符模板:
template <helper str> // placeholder type for deduction
constexpr auto operator""_S()
return str.string;
static_assert("foo"_S == std::array'f', 'o', 'o');
C++20 还没有最终确定,所以我不能确定。
【讨论】:
谢谢。是的,这就是(大约)C++2x 的帮助方式。希望这将在 C++20 中被“投票”。一个反驳的论点,我实际上记得读过这可能“给编译器供应商带来压力”。如果我没记错的话,假设是该功能可能允许某些人以这种方式创建“大量文本”。但是,这我们已经可以做到了。不确定不向 UDL 提供接收本机数组引用的简单签名的目的是什么/目的是什么,例如,自 C++11 起 @ChefGladiator 我认为这是当前草案所说的,所以它可能已经被投票了。此外,如果你觉得它有用,你可以投票(并选择接受它),以防万一你不知道。以上是关于另一个字符串文字,UDL 迷宫的主要内容,如果未能解决你的问题,请参考以下文章