下面的操作不起作用,因为Int
有一个const成员,并且=
操作符被删除,因为它不能修改值:
struct Int {
const int val = 1;
Int(int val) : val(val) {}
operator int() {
return val;
}
};
std::vector<Int> ints = {1, 2, 3, 4};
Int sum = 0;
for (Int i : ints) { sum = sum+i; }
std::cout << sum;
字符串
如果我尝试使用std::accumulate
,也会出现同样的问题。
我可以通过将sum
设置为智能指针来解决这个问题,但它看起来很笨拙。有更好的方法吗?
3条答案
按热度按时间gjmwrych1#
如果我尝试使用
std::accumulate
,也会出现同样的问题。不,它不会,如果你正确使用它。
字符串
Live Demo
返回类型和
accu
可以是与元素不同的类型。返回类型由初始值0
确定,为int
。你可以在你的手写循环中做同样的事情:
型
如果你想修改成员,不要让他们成为
const
。虽然,你不需要修改它来累积它。而且,operator int
应该是const
。假设用例是我想删除const,但出于某种原因我不能。
那么解决的办法就是不要使用
Int
。它可以被认为是坏了不止一个原因。aurhwmvo2#
我有一个类型的对象列表,其中有一些const成员,我想得到一个相同类型的对象,它是列表的某种积累,例如一个sum。
我并不是在寻找“使其成为非常数”的解决方案,也没有必要让这个问题过于具体。
概念上,这可以通过左(或右)折叠来完成,这只是一个递归调用,不涉及任何赋值。这里是cppreference page for fold_left_first in C++23。
左折叠给定范围的元素,即返回链表达式的求值结果:f(f(f(x1,x2),x3),...),xn),
但是,标准库中的
fold_left_first
仍然需要std::movable<T>
,而std::assignable_from<T&, T>
又需要Int
,Int
会因为这个约束而失败,所以即使我们有C++23也不能直接在这里使用。不过,您也可以编写自己的
fold_left_first
版本,而不受这些限制,如下所示:字符串
fold_left_first
遵循与标准版本相同的语义,并返回std::optional
以指示可能为空的范围。您可以调整它以满足您的需求。然而,正如其他人评论的那样,通常建议避免使用const和reference成员,但既然你已经声明删除它们不是一个选项,这是我能得到的最好的而不失一般性。
演示:https://godbolt.org/z/Kojc1MvKr
vyswwuz23#
它只是一个概念(例如,缺少移动语义),但您可以创建一个 Package 器,该 Package 器根据需求/分配创建/销毁对象。
当然,如果构造函数/析构函数不便宜,这个解决方案也不会神奇地便宜。
个字符