C++ 如何在size\u t上使用余数运算符获得负余数?

C++ 如何在size\u t上使用余数运算符获得负余数?,c++,implicit-conversion,size-t,C++,Implicit Conversion,Size T,考虑以下代码示例: #include <iostream> #include <string> int main() { std::string str("someString"); // length 10 int num = -11; std::cout << num % str.length() << std::endl; } 这可能有效,但不能保证,例如,对于长度大于最大值int的字符串。可以使用较大的类型(如l

考虑以下代码示例:

#include <iostream>
#include <string>

int main()
{
    std::string str("someString"); // length 10
    int num = -11;
    std::cout << num % str.length() << std::endl;
}
这可能有效,但不能保证,例如,对于长度大于最大值
int
的字符串。可以使用较大的类型(如
long-long
)来降低风险,但是如果
size\u t
unsigned long
?同样的问题


如何以可移植且健壮的方式解决此问题?

自C++11以来,您可以将
length
的结果强制转换为
std::string::difference\u type

要解决“但是如果尺寸太大怎么办?”:

这在64位平台上是不会发生的,即使您使用的是较小的平台:上一次使用占总RAM一半以上的字符串是什么时候?除非你做的是真正具体的事情(你会知道的),否则使用
difference\u类型就可以了;别跟鬼魂打了

或者,只需使用
int64\u t
,这当然足够大了。(虽然在某些32位处理器上循环一个比
int32\u t
慢,但我不知道。但这对单模运算来说并不重要。)

(有趣的事实):即使是一些重要的委员会成员也会考虑把标准库用无符号类型乱扔,以供参考。 9:50、42:40、1:02:50)

在C++11之前,带有负值的
%
符号是实现定义的,对于定义良好的行为,使用加上上面描述的一个强制转换。

我们知道

-a % b == -(a % b)
所以你可以这样写:

template<typename T, typename T2>
constexpr T safeModulo(T a, T2 b)
{
    return (a >= 0 ? 1 : -1) * static_cast<T>(std::llabs(a) % b);
}
如果
std::size\u t
实现为
unsigned long
,则
T2->unsigned long
t->int

正如评论中指出的,使用
std::llabs
而不是
std::abs
是很重要的,因为如果
a
int
的最小可能值,移除符号将溢出。将
a
升级为
long
不会导致此问题,因为
long
的值范围更大

现在
static\u cast(std::llabs(a)%b)
将始终导致小于
a
的值,因此将其强制转换为
int
将永远不会溢出/下溢。即使
a
被提升为
unsigned long
,这也无关紧要,因为
a
已经从
std::llabs(a)
中“unsigned”,因此该值保持不变(即没有溢出/下溢)

由于上述属性,如果
a
为负数,则将结果乘以
-1
,即可得到正确的结果



导致未定义行为的唯一情况是
a
std::numeric\u limits::min()
,因为删除符号溢出
a
,导致未定义行为。可能还有另一种实现函数的方法,我会考虑。

它是一个余数运算符。行为取决于你使用的标准版本。C代码在1999之前写,C++代码在2011之前写的可能不一致,因为在旧的标准中否定的除法/余数很不好。确保使用现代编译器/标准。虽然大小可以表示为long-long,但我怀疑它是否会最大化。除非您的平台支持exa字节字符串长度,即。。。我认为这在任何情况下都是一个合理的限制。谢谢,这是有道理的,但是如果a是
INT\u MIN
,这不会导致未定义的行为吗@埃尔尼不,是的,我完全忘了那个案子。将
a
升级为
long
将导致定义的行为。谢谢:)感谢您对
差异类型的深入了解。如果我理解正确,按照标准,
size\u t
大到足以表示字符串的长度,而
difference\u type
大到足以表示同一字符串上两个迭代器之间可能存在的最大差异;由于最大差异是字符串的长度,因此将
size\u t
转换为
difference\u type
应该是安全的。正确吗?“
difference\u type
足够大,可以表示同一字符串上两个迭代器之间可能存在的最大差异;”实际上,这几乎成立,但不能保证。在32位系统上,
size\u t
和差分类型很可能都是32位整数,因此如果字符串大小为2.5GB或更大,则该大小将不适合有符号字符串。
template<typename T, typename T2>
constexpr T safeModulo(T a, T2 b)
{
    return (a >= 0 ? 1 : -1) * static_cast<T>(std::llabs(a) % b);
}
safeModulo(num, str.length());