如何在 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
他们似乎都想推动我使用以下模板,该模板曾经被简单地认为是 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")
根据我的 (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
他们似乎都想推动我使用以下模板,该模板曾经被简单地认为是 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")