如何在 C++17 中定义用户定义的字符串文字运算符模板?

How do you define user-defined string literal operator templates in C++17?

根据我的 (draft) version of C++17 (16.5.8 [over.literal]) as well as as cppreference.com,C++17 应该 支持用户定义的字符串文字的模板化运算符。

具体来说:

template <char...>
double operator "" _pi() {
    return 0.;
}

int main() {
  "test"_pi;
}

然而gcc和clang都骂我:

// gcc -Wall -Wextra -pedantic -std=c++17
error: no matching function for call to 'operator""_pi<char, 't', 'e', 's', 't'>()'
    7 |   "test"_pi;
      |   ^~~~~~~~~
note: candidate: 'template<char ...<anonymous> > double operator""_pi()'
    2 | double operator "" _pi() {

// clang -Wall -Wextra -pedantic -std=c++17
error: no matching literal operator for call to 'operator""_pi' with arguments of types 'const char *' and 'unsigned long', and no matching literal operator template

(live demo)

他们似乎都想推动我使用以下模板,该模板曾经被简单地认为是 C++17 的一部分,但据我所知并没有成为它的一部分:

template <typename T, T...>
double operator "" _pi() {
    return 0.;
}

然而,gcc 和 clang 都正确地警告这是一个非标准的扩展,但它们编译正确。 gcc and clang 都声称完全支持 C++17 核心语言。

我做错了什么?我的草稿 AND cppreference.com 不准确吗?我目前无法访问最终标准版本。


用例

我的用例是实现以下,这就是我需要编译时信息的原因。

template <char... cs>
constexpr auto operator "" _a() {
  return std::array<char, sizeof...(cs)>({cs...});
}
// "Hello"_a creates a std::array<char,5>

模板char... 用户定义文字不适用于字符串。它被称为数字文字运算符模板,它允许您拥有一个文字运算符,它将获取您正在使用的数字并将其扩展为模板运算符的包。例如,您可以使用

这样的运算符
1234_pi

这将解决调用

operator "" <'1', '2', '3', '4'> _pi()

你想要的东西在现有的 C++17 中是不可能的

要让它工作,您需要升级到 C++20,它允许您使用可以从字符串文字构造的用户定义类型,并使用它来构建 std::array.这就是现在所谓的字符串文字运算符模板。 看起来像

template<std::size_t N>
struct MakeArray
{
    std::array<char, N> data;
    
    template <std::size_t... Is>
    constexpr MakeArray(const char (&arr)[N], std::integer_sequence<std::size_t, Is...>) : data{arr[Is]...} {}
 
    constexpr MakeArray(char const(&arr)[N]) : MakeArray(arr, std::make_integer_sequence<std::size_t, N>())
    {}
};
 
template<MakeArray A>
constexpr auto operator"" _foo()
{
    return A.data;
}

然后

"test"_foo;

这将解析为 std::array<char, 5>。如果你不想在数组中使用空终止符,你只需要从 N 中减去 1 除了 char const(&arr)[N] 部分之外的任何地方。

如果你不能使用 C++20,你可以将它切换到几个函数,比如

template <std::size_t N, std::size_t... Is>
constexpr auto as_array_helper(const char (&arr)[N], std::integer_sequence<std::size_t, Is...>)
{
    return std::array<char, N>{arr[Is]...};
}

template <std::size_t N>
constexpr auto as_array(const char (&arr)[N])
{
    return as_array_helper(arr, std::make_integer_sequence<std::size_t, N>());
}

然后你会像

一样使用它
as_array("test")