假设我想从中删除唯一元素std::vector(不消除重复项,而仅保留至少出现2次的元素),并且我想以一种非常低效的方式实现这一点-通过std::count在std::remove_ifing时调用。考虑以下代码:
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec = {1, 2, 6, 3, 6, 2, 7, 4, 4, 5, 6};
auto to_remove = std::remove_if(vec.begin(), vec.end(), [&vec](int n) {
return std::count(vec.begin(), vec.end(), n) == 1;
});
vec.erase(to_remove, vec.end());
for (int i : vec) std::cout << i << ' ';
}
Run Code Online (Sandbox Code Playgroud)
从参考开始,std::remove_if我们知道从开始的元素to_remove具有未指定的值,但是我想知道它们到底有多未指定。
为了解释我所关心的远一点-我们可以看到,应删除的元素是1,3,5和7-唯一的唯一值。std::remove_if会将移至 …
我们知道它void*没有关于它指向的数据的实际类型的信息。但是,从 cppreference 开始new,new[]我们知道这些运算符返回void*. 那么,如何给出:
auto x = new int{};
Run Code Online (Sandbox Code Playgroud)
知道new操作符应该返回void*,x被推导为一种类型int*,不是void*吗?
再考虑一个例子:
struct foo {
static void* operator new(std::size_t n) {
std::cout << "new called!\n";
return ::new char[n];
}
};
Run Code Online (Sandbox Code Playgroud)
让我们添加一些牛逼YPE d isplayer:
template <typename T>
struct TD;
Run Code Online (Sandbox Code Playgroud)
和测试代码:
int main() {
auto x = new foo{};
TD<decltype(x)>{};
}
Run Code Online (Sandbox Code Playgroud)
代码无法编译,错误指示decltype(x)是foo*。如果我们注释掉 的最后一行main,我们就会知道我们的void*-returning 操作符会因为new …
看std::for_each_n的可能的实现:
template<class InputIt, class Size, class UnaryFunction>
InputIt for_each_n(InputIt first, Size n, UnaryFunction f)
{
for (Size i = 0; i < n; ++first, (void) ++i) {
f(*first);
}
return first;
}
Run Code Online (Sandbox Code Playgroud)
我注意到我们通常看到的部分i++(或首选++i)由两个操作组成:
++first(void) ++i用逗号分隔。虽然大部分都说得通,但(void)演员阵容对我来说似乎有点令人惊讶。我只能猜测是,有可能是超载operator ,,是以推导型的InputIt和Size这将导致一些令人吃惊的副作用。这可能是原因吗?如果是,我们确定演员void阵容完全解决了这个问题吗?
如果我们有:
void foo(int) {}
void foo(const int&) {}
Run Code Online (Sandbox Code Playgroud)
我们不能这样调用foo:
foo(3);
Run Code Online (Sandbox Code Playgroud)
因为调用是模棱两可的:
Run Code Online (Sandbox Code Playgroud)error: call of overloaded 'foo(int)' is ambiguous 40 | foo(3); | ^ note: candidate: 'void foo(int)' 36 | void foo(int) {} | ^~~ note: candidate: 'void foo(const int&)' 37 | void foo(const int&) {} | ^~~
我们可以做的是明确提供正确的重载,例如通过函数指针:
auto (*ptr)(const int&) -> void = foo;
ptr(3); // calls the "const int&" overload, obviously
Run Code Online (Sandbox Code Playgroud)
然而,这种方式违背了方便重载的目的。问题是 - 我可以以某种方式以更......优雅的方式消除呼叫的歧义吗?道路?是否有过哪里会需要提供案件都过载,为T和const T& …
对于以下代码:
#include <iostream>
#include <string>
#include <ranges>
int main()
{
std::string s = " text ";
auto sv = std::ranges::views::split(s, ' ');
std::cout << std::ranges::distance(sv.begin(), sv.end());
}
Run Code Online (Sandbox Code Playgroud)
输出为 2。输出范围中不存在最后一个分隔符之后的空子范围。
这似乎不一致,因为N+1如果N输入范围中出现分隔符,我希望输出范围中有子范围。为什么不是这样?
请注意 range-v3 做的完全一样,所以我确定这是故意的,但我想知道为什么。
我写了一个简单的谓词,我想传递给std::ranges::views::filter:
struct even_fn {
constexpr
bool operator()(std::integral auto&& e) const noexcept {
return e % 2 == 0;
}
};
inline constexpr even_fn even;
Run Code Online (Sandbox Code Playgroud)
示例用法:
using namespace std::ranges;
views::iota(1, 10) | views::filter(even);
Run Code Online (Sandbox Code Playgroud)
这失败了一大堆错误,我认为最有意义的错误是:
Run Code Online (Sandbox Code Playgroud)note: the expression 'is_invocable_v<_Fn, _Args ...> [with _Fn = even_fn&; _Args = {std::__detail::__cond_value_type<int>::value_type&}]' evaluated to 'false'
但是,如果我std::integral从我的操作员中删除该部分(只留下auto&&),代码将成功编译。这是为什么?__cond_value_type当我们有约束函子时,它有什么特别之处呢?
我正在尝试根据某种类型以及它们是否按顺序对列表进行分组
data class Item(val type: Int, val name: String)
private fun splitItems(items: List<Item>): List<List<Item>> {
val groupedItems = mutableListOf<List<Item>>()
var tempList = mutableListOf<Item>()
items.mapIndexed { index, item ->
if (index > 0) {
val previousItem = items[index - 1]
if (previousItem.type == item.type) {
tempList.add(item)
} else {
if (tempList.isNotEmpty()) groupedItems.add(tempList)
tempList = mutableListOf()
tempList.add(item)
}
} else tempList.add(item)
}
if (tempList.isNotEmpty()) groupedItems.add(tempList)
return groupedItems
}
Run Code Online (Sandbox Code Playgroud)
现在这个乐趣将需要
val items = mutableListOf(
Item(1, "Shirt"),
Item(1, "Shirt"),
Item(2, "Pant"),
Item(2, "Pant"),
Item(2, …Run Code Online (Sandbox Code Playgroud) 基本生活/8告诉我们,我们可以在一个对象的生命周期结束后,使用它所占用的存储空间来创建一个新的对象,并使用它原来的名称来引用它,除非:
\n\n\n\n
\n- 原始对象的类型不是 const 限定的,并且,如果是类类型,则不包含任何类型为 const 限定的非静态数据成员或引用类型,并且 [...]
\n
强调我的
\n但是,就在其下方,我们可以看到一条注释:
\n\n\n\n
\n- 如果不满足这些条件,则可以通过调用从表示其存储地址的指针获得指向新对象的指针
\nstd\xe2\x80\x8b::\xe2\x80\x8blaunder
这解释了的目的std::launder。我们可以有一个类类型const,并使用placement-new 来创建一个具有不同内部值的新对象。
让我惊讶的是第一句话的第一部分。它清楚地表明,如果存储是const(不一定包含const成员,但整个对象被声明为const),我们不能用它来引用一个新对象,但这可能意味着std::launder可以修复它。
但我们如何创建这样的对象呢?最简单的例子失败了:
\nconst auto x = 5;\nnew (&x) auto(10);\nRun Code Online (Sandbox Code Playgroud)\n这是因为我们不能用作const void*新放置的缓冲区。我们可以const_cast做到,但抛弃“真实”const性就是未定义的行为。我相信这里也是如此。
如果只是禁止使用const对象作为放置新缓冲区,我会理解,但如果是这样,那么第一个引用中强调的部分的目的是什么?我们能否真正利用重用const对象的存储重用于不同的对象吗?
float do_bad_things(int n) {
alignof(int) alignof(float)
char buffer[max(sizeof(int), sizeof(float))];
*(int*)buffer = n; // #1
new (buffer) std::byte[sizeof(buffer)];
return *(float*)buffer; // #2
}
Run Code Online (Sandbox Code Playgroud)
并指出:
提议的规则将允许一个
int对象突然出现以使第 #1 行有效 [...],并且将允许一个float对象同样突然出现以使第 #2 行有效。然而,这些示例在提议的规则下仍然没有定义行为。原因是 [basic.life]p4 的结果:
本文档中赋予对象和引用的属性仅在给定对象或引用的生命周期内适用。
具体来说,对象所持有的值仅在其整个生命周期内保持稳定。
int当第 #1 行中的对象的生命周期结束时(当第 #2 行中的对象重用其存储时float),它的值就消失了。对称地,当创建 float 对象时,该对象具有不确定的值 ([dcl.init]p12),因此任何加载其值的尝试都会导致未定义的行为。
强调我的
该提案声称有问题的部分是float对象的(隐式)创建。但是上一行 ( new (buffer) std::byte[sizeof(buffer)]) 不是已经重用了存储(通过创建数组),结束了相关byte的生命周期吗?int据我了解,安置总是新的结束内存中创建新对象的对象的生命周期。
另外,这个评论说“新表达式不承诺保留存储中的字节。 ”这是否意味着new (buffer) std::byte[sizeof(buffer)]理论上可以改变 …
我想逐列查看 3x3 网格,所以我想我会std::views::stride像这样使用:
#include <array>
#include <iostream>
#include <ranges>
auto main() -> int {
auto grid = std::array<std::array<int, 3>, 3>{{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
}};
namespace vs = std::views;
auto strideCount = grid.size();
auto allElements = grid | vs::join;
auto columns = vs::iota(0uz, strideCount)
| vs::transform([allElements, strideCount](auto n) {
return allElements
| vs::drop(n)
| vs::stride(strideCount);
});
for (auto&& column : columns) {
for (auto element : column) {
std::cout << element << ' …Run Code Online (Sandbox Code Playgroud) c++ ×9
c++20 ×2
c++23 ×2
std-ranges ×2
algorithm ×1
c++-concepts ×1
casting ×1
for-loop ×1
kotlin ×1
lifetime ×1
range-v3 ×1
stdlaunder ×1
stdvector ×1