带有字符串文字的前缀与中缀运算符*
Prefix vs infix operator* with string literals
我最近给出了一个 answer to this question 如何获得 Python-like 字符串重复,例如"hello" * 2
给出 "hellohello"
.
这里不再重复定义,函数声明为:
std::string repeat(std::string str, const std::size_t n);
当然可以这样使用:
std::cout << repeat("helloworld", 2) << std::endl;
为了更接近 Python 版本,我想我应该重载 operator*
。理想情况下,我会使用通用参考来避免额外的 std::string
移动,但是 operators must use a user-defined type。所以我改用这个:
#include <type_traits> // std::enable_if_t, std::is_integral
#include <utility> // std::move
template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
std::string operator*(std::string str, const T n)
{
return repeat(std::move(str), static_cast<std::size_t>(n));
}
现在我可以做到了:
std::cout << (std::string("helloworld") * 2) << std::end;
还有这个:
std::cout << operator*("helloworld", 2) << std::endl;
但不是这个:
std::cout << ("helloworld" * 2) << std::endl;
// error: invalid operands to binary expression ('const char *' and 'int')
为什么不呢?
因为 "helloworld"
不是 std::string
,它是 char
数组。
定义重载运算符时,至少有一个操作数必须是用户定义的类型。对于预定义类型,所有运算符要么是预定义的,要么是禁止的。
在您显式转换为 std::string
的地方,使用 char const *
作为其参数的 string
构造函数 can/will 用于将文字转换为 std::string
,但如果没有它,编译器就不能't/won进行转换。
同样,当您更明确地调用运算符 operator*("helloworld", 2)
时,编译器 "knows" 需要将字符串文字转换为 operator *
重载支持的类型,所以它(基本上)枚举了字符串文字可以转换成的所有类型,然后查看它是否可以找到适合其中一种类型的 operator *
。如果它找到多个,它会(如果内存可用)对候选 operator *
实现进行正常的重载解析,以决定使用哪个。
然而,仅使用表达式 string-literal * int
,两种类型都是内置的,因此它仅检查内置运算符。由于 none 个符合,因此表达式被禁止。
请注意,使用当前的编译器,您可以在字符串文字上使用 s
后缀来创建 std::string
:
#include <string>
std::cout << "helloworld"s * s << "\n";
我最近给出了一个 answer to this question 如何获得 Python-like 字符串重复,例如"hello" * 2
给出 "hellohello"
.
这里不再重复定义,函数声明为:
std::string repeat(std::string str, const std::size_t n);
当然可以这样使用:
std::cout << repeat("helloworld", 2) << std::endl;
为了更接近 Python 版本,我想我应该重载 operator*
。理想情况下,我会使用通用参考来避免额外的 std::string
移动,但是 operators must use a user-defined type。所以我改用这个:
#include <type_traits> // std::enable_if_t, std::is_integral
#include <utility> // std::move
template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
std::string operator*(std::string str, const T n)
{
return repeat(std::move(str), static_cast<std::size_t>(n));
}
现在我可以做到了:
std::cout << (std::string("helloworld") * 2) << std::end;
还有这个:
std::cout << operator*("helloworld", 2) << std::endl;
但不是这个:
std::cout << ("helloworld" * 2) << std::endl;
// error: invalid operands to binary expression ('const char *' and 'int')
为什么不呢?
因为 "helloworld"
不是 std::string
,它是 char
数组。
定义重载运算符时,至少有一个操作数必须是用户定义的类型。对于预定义类型,所有运算符要么是预定义的,要么是禁止的。
在您显式转换为 std::string
的地方,使用 char const *
作为其参数的 string
构造函数 can/will 用于将文字转换为 std::string
,但如果没有它,编译器就不能't/won进行转换。
同样,当您更明确地调用运算符 operator*("helloworld", 2)
时,编译器 "knows" 需要将字符串文字转换为 operator *
重载支持的类型,所以它(基本上)枚举了字符串文字可以转换成的所有类型,然后查看它是否可以找到适合其中一种类型的 operator *
。如果它找到多个,它会(如果内存可用)对候选 operator *
实现进行正常的重载解析,以决定使用哪个。
然而,仅使用表达式 string-literal * int
,两种类型都是内置的,因此它仅检查内置运算符。由于 none 个符合,因此表达式被禁止。
请注意,使用当前的编译器,您可以在字符串文字上使用 s
后缀来创建 std::string
:
#include <string>
std::cout << "helloworld"s * s << "\n";