数字 UDL 运算符模板

Numeric UDL operator template

我正在尝试定义 Pablo Halpern calls 数字 UDL 运算符模板。我希望它成为 return 一个 lambda,它会计算 char 数组开头有多少个字符来自给定的集合。

这是我的测试代码:

template <char... c>
constexpr auto operator ""_cntany() {
  return [](const char* s){
    unsigned n = 0;
    while (((*s==c) || ...)) { ++n; ++s; }
    return n;
  };
}

int main(int argc, char** argv) {
  return ("test"_cntany)(argv[1]);
}

但这不能用 GCC 11.2 (https://godbolt.org/z/TdbKzTMW8) 编译。 这是我收到的错误:

<source>: In function 'int main(int, char**)':
<source>:11:15: error: no matching function for call to 'operator""_cntany<"test">()'
  11 |       return ("test"_cntany)(argv[1]);
      |               ^~~~~~~~~~~~~
<source>:2:20: note: candidate: 'template<char ...c> constexpr auto operator""_cntany()'
    2 |     constexpr auto operator ""_cntany() {
      |                    ^~~~~~~~
<source>:2:20: note:   template argument deduction/substitution failed:
<source>:11:15: error: '"test"' is not a valid template argument for type 'char' because string literals can never be used in this context
  11 |       return ("test"_cntany)(argv[1]);
     |               ^~~~~~~~~~~~~
Compiler returned: 1

我做错了什么?

cppreference

If the literal operator is a template, it must have an empty parameter list and can have only one template parameter, which must be a non-type template parameter pack with element type char (in which case it is known as a numeric literal operator template)

template <char...> double operator "" _x();

另见 [over.literal.5]

即它是数字,而不是字符串文字。

可以123_cntany一样使用。

注意,有一个新的 C++20 字符串文字运算符模板:

不幸的是,C++ 没有用于具有该模板格式的字符串的 udl。

gcc 有一个 extension template <typename Char, Char... c>

所以会是

template <typename Char, Char... c>
constexpr auto operator ""_cntany() {
  return [](const char* s){
    unsigned n = 0;
    while (((*s==c) || ...)) { ++n; ++s; }
    return n;
  };
}

但它作为扩展不可移植。

模板 user-defined 文字需要接受 数字 值,例如 0123_cntany,因此您可能只需要使用 user-defined string-literal:

#include <cstddef>
#include <string_view>

constexpr auto operator ""_cntany(const char* s, std::size_t count) {
  return [sv = std::string_view(s, count)](const char* s){
    unsigned n = 0;
    while (sv.contains(*s)) { ++n; ++s; }
    return n;
  };
}