何时以及如何使用模板文字运算符?
When and how to use a template literal operator?
在 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
, such as
template <char...> double operator "" _x();
所以我在下面的代码中写了一个:
template <char...>
double operator "" _x()
{
return .42;
}
int main()
{
10_x; // empty template list, how to specify non-empty template parameters?
}
问题:
- 代码有效,但如何使用带有一些非空模板参数的运算符?
10_x<'a'>;
或 10_<'a'>x;
不编译。
- 您有任何此类模板化运算符在现实世界中的使用示例吗?
10_x; // empty template list, how to specify non-empty template parameters?
这不太正确。模板参数列表不为空。当你写:
template <char... Cs>
??? operator "" _x()
Cs
由文字左侧的内容填充。也就是说,当你写:
10_x
调用:
operator ""_x<'1', '0'>();
一个简单的例子是构建一个编译时、溢出安全的二进制文字,这样:
template <uint64_t V>
constexpr uint64_t make_binary() {
return V;
}
template <uint64_t V, char C, char... Cs>
constexpr uint64_t make_binary() {
static_assert(C == '0' || C == '1', "invalid binary");
return make_binary<2*V + C - '0', Cs...>();
}
template <char... Cs>
uint64_t operator "" _b()
{
static_assert(sizeof...(Cs) <= 64, "overflow");
return make_binary<0, Cs...>();
}
uint64_t a = 101_b; // OK: a == 5
uint64_t b = 102_b; // error: invalid
uint64_t c = 11111111110000000000111111111100000000001111111111000000000011111111110000000000_b; // error: overflow
您的模板参数已经指定——它们是构成您的字面值的源代码字符!所以对于 10_x
,你实际上是在调用:
template<> double operator "" _x<'1', '0'>();
这是一个工作示例。它编译没有错误,并且触发了 none 个断言。
#include <cassert>
enum class MyEnum
{
ONE,
TWO,
THREE
};
template<char...> MyEnum operator "" _e();
template<> MyEnum operator "" _e<'1'>()
{
return MyEnum::ONE;
}
template<> MyEnum operator "" _e<'2'>()
{
return MyEnum::TWO;
}
template<> MyEnum operator "" _e<'3'>()
{
return MyEnum::THREE;
}
int main()
{
assert(1_e == MyEnum::ONE);
assert(2_e == MyEnum::TWO);
assert(3_e == MyEnum::THREE);
}
您可以以某种方式详细说明参数包(正如其他人所提到的),或者如果您愿意,可以将它们作为编译时字符串访问:
template<int N>
constexpr double f(const char(&str)[N]) { return .42; }
template <char... C>
constexpr double operator "" _x()
{
return f({C...});
}
Do you have any example of real-world usage of such templated operators?
你可以使用上面提到的技术来处理编译时 string-to-num 转换器,并且有类似 10_x
而不是 f("10")
的东西或其他。
在 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
, such as
template <char...> double operator "" _x();
所以我在下面的代码中写了一个:
template <char...>
double operator "" _x()
{
return .42;
}
int main()
{
10_x; // empty template list, how to specify non-empty template parameters?
}
问题:
- 代码有效,但如何使用带有一些非空模板参数的运算符?
10_x<'a'>;
或10_<'a'>x;
不编译。 - 您有任何此类模板化运算符在现实世界中的使用示例吗?
10_x; // empty template list, how to specify non-empty template parameters?
这不太正确。模板参数列表不为空。当你写:
template <char... Cs>
??? operator "" _x()
Cs
由文字左侧的内容填充。也就是说,当你写:
10_x
调用:
operator ""_x<'1', '0'>();
一个简单的例子是构建一个编译时、溢出安全的二进制文字,这样:
template <uint64_t V>
constexpr uint64_t make_binary() {
return V;
}
template <uint64_t V, char C, char... Cs>
constexpr uint64_t make_binary() {
static_assert(C == '0' || C == '1', "invalid binary");
return make_binary<2*V + C - '0', Cs...>();
}
template <char... Cs>
uint64_t operator "" _b()
{
static_assert(sizeof...(Cs) <= 64, "overflow");
return make_binary<0, Cs...>();
}
uint64_t a = 101_b; // OK: a == 5
uint64_t b = 102_b; // error: invalid
uint64_t c = 11111111110000000000111111111100000000001111111111000000000011111111110000000000_b; // error: overflow
您的模板参数已经指定——它们是构成您的字面值的源代码字符!所以对于 10_x
,你实际上是在调用:
template<> double operator "" _x<'1', '0'>();
这是一个工作示例。它编译没有错误,并且触发了 none 个断言。
#include <cassert>
enum class MyEnum
{
ONE,
TWO,
THREE
};
template<char...> MyEnum operator "" _e();
template<> MyEnum operator "" _e<'1'>()
{
return MyEnum::ONE;
}
template<> MyEnum operator "" _e<'2'>()
{
return MyEnum::TWO;
}
template<> MyEnum operator "" _e<'3'>()
{
return MyEnum::THREE;
}
int main()
{
assert(1_e == MyEnum::ONE);
assert(2_e == MyEnum::TWO);
assert(3_e == MyEnum::THREE);
}
您可以以某种方式详细说明参数包(正如其他人所提到的),或者如果您愿意,可以将它们作为编译时字符串访问:
template<int N>
constexpr double f(const char(&str)[N]) { return .42; }
template <char... C>
constexpr double operator "" _x()
{
return f({C...});
}
Do you have any example of real-world usage of such templated operators?
你可以使用上面提到的技术来处理编译时 string-to-num 转换器,并且有类似 10_x
而不是 f("10")
的东西或其他。