C++ 用户定义的字符串文字模板奇怪的问题(获取字符串文字长度作为编译时常量)

gre*_*ekd 2 c++ gcc clang user-defined-literals c++20

我正在尝试定义用户定义的字符串文字模板。

该代码片段不应该起作用吗?/ 为什么不起作用?

template<char...>
constexpr
int operator ""_x () {
    return 0;
}

int x = "abc"_x;
Run Code Online (Sandbox Code Playgroud)

运算符声明被编译器“接受”为有效 - C++ 对用户定义的文字非常严格,任何与规范声明的偏差都会被诊断为错误。因此,接受该声明对我来说表明它很好 - 正如我所期望的 - 但我尝试过的编译器(GCC、Clang、MSVC - godbolt.org 上的所有trunk)都没有编译使用下一个定义运算符,其中 Clang 和 MSVC 找不到匹配的文字运算符,而 GCC 给出了一个令人惊讶的奇怪错误(你可以在godbolt.org上看到完整的错误),其中部分:

(...)
<source>:7:9: error: type/value mismatch at argument 1 in template parameter list for 'template<char ...<anonymous> > constexpr int operator""_x()'
    7 | int x = "abc"_x;
      |         ^~~~~~~
<source>:7:9: note:   expected a constant of type 'char', got 'char'
Run Code Online (Sandbox Code Playgroud)

(编译器说)我预料到了char,但是我得到了char......Maaan......我不知道现在该怎么办!- 最令人困惑的...

我在这个项目中使用 Clang 15,因此如果有针对此问题的编译器特定修复程序,我将不胜感激。

编辑:根据第一个答案 - 我必须补充一点,这是显示问题的最小片段,而不是该函数的目标用例 - 它是一个模板至关重要 - 更具体地说:我想实现多 -字符文字运算符,但不幸的是,定义 C++ 规范的人决定禁止int16/int32类型被接受为用户定义的文字参数,它们是 Clang 的 'ab'/'abc'/'abcd' 的基础类型,我决定将其通过使用字符串文字(“”)而不是字符一('')来解决,但为了使其工作,我需要在编译时限制源字符串文字的可接受长度,(据我所知)仅当文字作为模板参数传递时,才可以在 C++ 中使用。

S.M*_*.M. 5

在这种情况下,您不需要模板。

#include <string>

constexpr int operator""_x (const char* str, std::size_t) {
  return 0;
}

int x = "abc"_x;
Run Code Online (Sandbox Code Playgroud)

模板用于转换字符串文字以外的文字:

template<char...>
constexpr
int operator ""_x () {
    return 0;
}

int x = 10_x;
Run Code Online (Sandbox Code Playgroud)

根据问题中的新信息,限制可接受的字符串文字长度:

#include <string>
 
template<std::size_t N>
struct StringLiteral {
  char s[N]{};
  constexpr StringLiteral(char const(&p)[N]) {
    // restrict the acceptable length with 4 chars + terminator
    static_assert(N <= 5);
    std::copy(p, p + N, s);
  }
};
 
template<StringLiteral L>
constexpr int operator""_x() {
  // Use L.s
  return 0;
}
 
int x = "abc"_x;
Run Code Online (Sandbox Code Playgroud)

https://godbolt.org/z/nvj1GGjbM

或者使结构与字符串文字长度无关:

#include <string>
 
template<std::size_t N>
struct StringLiteral {
  char s[N]{};
  std::size_t n{};
  constexpr StringLiteral(char const(&p)[N]) : n(N) {
    std::copy(p, p + N, s);
  }
};
 
template<StringLiteral L>
constexpr int operator""_x() {
  // restrict the acceptable length with 4 chars + terminator
  static_assert(L.n <= 5);
  // Use L.s
  return 0;
}

int x = "abc"_x;
Run Code Online (Sandbox Code Playgroud)

https://godbolt.org/z/hdP4aoefn