这是我(简化)尝试实现一个ranges::min_element适用于左值和右值参数的版本:
#include <iterator>
#include <algorithm>
#include <type_traits>
#include <utility>
namespace better_std_ranges
{
template<typename Range>
constexpr auto min_element(Range& range)
{
using std::begin;
using std::end;
return std::min_element(begin(range), end(range));
}
template<typename Range>
constexpr auto min_element(Range&& range)
{
static_assert(!std::is_reference_v<Range>, "wrong overload chosen");
class _result_iterator_type // todo: inherit from some crtp base that will provide lacking operators depending on _underlying_iterator_type::iterator_category
{
using _underlying_iterator_type = std::decay_t<decltype(std::begin(std::declval<Range&>()))>;
public:
explicit constexpr _result_iterator_type(Range&& range) noexcept(std::is_nothrow_move_constructible_v<Range>)
: _underlying_range{std::move(range)}
, _underlying_iterator(::better_std_ranges::min_element(_underlying_range))
{
}
using difference_type = typename _underlying_iterator_type::difference_type;
using …Run Code Online (Sandbox Code Playgroud) 此示例程序无法编译,因为transform_view无法转换为std::span:
class Foo {
private:
std::vector<std::string> strings = { "a", "b", "c" };
public:
std::span<const char*> getStrings() {
return strings | std::views::transform([](const std::string& str) { return str.c_str(); });
}
};
int main() {
Foo foo;
auto strings = foo.getStrings();
for (auto s : strings)
std::cout << s << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
我知道还不可能构造容器(如std::vector),但是我不太明白,为什么不能从中构造 a std::span。我找到了这个答案,即目前唯一可以从任意范围构建的容器是std::span,所以我希望上面的例子能够工作。
有没有办法从范围创建跨度?或者有没有其他方法可以从方法返回通用视图,而不使用auto(虚拟方法不允许)?
我正在试验 C++20 范围,并且在使用 GCC 11.1.0 和 CMake 3.20.3 进行编译时出现了以下奇怪的行为。具体来说,以下代码无法编译:
auto Foo() {
std::vector<long int> x{1, 2, 3, 4, 5, 6};
return std::views::all(x) | std::views::take(x.size());
// return std::views::all(x) | std::views::take(static_cast<int>(x.size()));
}
Run Code Online (Sandbox Code Playgroud)
导致非常长的错误消息,例如
[...] error: no match for ‘operator|’ (operand types are ‘std::ranges::ref_view<std::vector<long int> >’ and ‘std::ranges::views::__adaptor::_Partial<std::ranges::views::_Take, long unsigned int>’)
[build] 230 | return std::views::all(x) | std::views::take(x.size());
[build] | ~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~
[build] | | |
[build] | | std::ranges::views::__adaptor::_Partial<std::ranges::views::_Take, long unsigned int>
[build] | std::ranges::ref_view<std::vector<long int> >
Run Code Online (Sandbox Code Playgroud)
和
[build] /usr/include/c++/11/ranges:739:13: required …Run Code Online (Sandbox Code Playgroud) 我正在看以下片段:
std::vector<int> elements{ 1,2,3 };
// this won't compile:
elements
| std::views::filter([](auto i) { return i % 2 == 0; })
| std::ranges::for_each([](auto e) {std::cout << e << std::endl; });
// but this compiles:
auto view =
elements
| std::views::filter([](auto i) { return i % 2 == 0; });
std::ranges::for_each(view, [](auto e) {std::cout << e << std::endl; });
Run Code Online (Sandbox Code Playgroud)
我看不出范围适配器(视图)和范围算法通过管道运算符的组合无法编译的原因。std::ranges::dangling我想这与我的编译器(msvc 19.29)报告的返回类型有关for_each,但我不确定......
我想要具有接受任何固定类型容器的功能。例如,一个函数将接受std::array<float,1>和std::array<float,2>。
我认为这在范围内是可能的,但我意识到我的理解非常肤浅。
我可以不使用模板吗?
编辑:我们可以使用范围库定义一个类型,该类型将执行与跨度相同的操作,但适用于非连续容器?也许我没有正确表达我的问题,我可能指的是视图而不是容器。
我一直在尝试了解新的范围库,并尝试将一些更传统的 for 循环转换为函数代码。cppreference给出的示例代码非常简单易读。但是,我不确定如何将范围应用于点向量,该点向量需要查看、计算并比较每个 x 和 y 值,并在最后比较最大距离。
struct Point
{
double x;
double y;
}
double ComputeDistance(const Point& p1, const Point& p2)
{
return std::hypot(p1.x - p2.x, p1.y - p2.y);
}
double GetMaxDistance(const std::vector<Point>& points)
{
double maxDistance = 0.0;
for (int i = 0; i < points.size(); ++i)
{
for(int j = i; j < points.size(); ++j)
{
maxDistance = std::max(maxDistance, ComputeDistance(points.at(i),points.at(j)));
}
}
return maxDistance;
}
Run Code Online (Sandbox Code Playgroud)
GetMaxDistance是我想尝试清理并应用范围的代码。我认为这就像做类似的事情一样简单:
double GetMaxDistance(const std::vector<Point>& points)
{
auto result = …Run Code Online (Sandbox Code Playgroud) 我正在尝试使用 C++20 范围和函数式编程加载目录中的所有 true-type 字体。但是,由于字体是一种资源,因此我在范围接口内分配内存。我想这就是 valgrind 认为我有泄漏的原因。我有一些std::views新分配的原始指针,最终会被丢弃 - 然而,这些原始指针被转换并复制到唯一指针的向量中。
有问题的代码:
// free a font resource
struct font_deleter {
void operator()(TTF_Font * font) { TTF_CloseFont(font); }
};
// aliases
using unique_font = std::unique_ptr<TTF_Font, font_deleter>;
using font_table = std::unordered_map<std::string, TTF_Font *>;
template<typename expected_t>
using result = tl::expected<expected_t, std::string>;
// determine if a path is a valid font file
auto _is_font_fxn(std::error_code & ec) {
return [&ec](fs::path const & path) {
return fs::is_regular_file(path, ec) and path.extension() == ".ttf";
};
} …Run Code Online (Sandbox Code Playgroud) 我注意到,许多算法可以与范围一起使用,允许使用自定义类型的成员,而不需要 lambda 函数。所以,我很好奇是否std::ranges可以有效地使用std::list<>. 我认识到这std::list<>不是此类算法的首选数据结构,但对于其他问题,它更适合我的目的。
下面的代码在 g++-11.3 下使用编译--std=c++20 -D_GLIBCXX_DEBUG并执行时,会产生有关迭代器的奇怪运行时错误。range我不太确定这意味着什么,但我怀疑它与返回时超出范围的向量有关test():range没有被移动或复制,而是无论管道运算符返回什么,都只保留对range.
#include <ranges>
#include <unordered_set>
#include <vector>
auto to_unordered_set(auto && range) {
using r_type = std::ranges::range_value_t<decltype(range)>;
auto common = range | std::views::common;
return std::unordered_set<r_type>(std::ranges::begin(common), std::ranges::end(common));
}
auto test() {
std::vector<int> range {1,2,3,4,5};
return range | std::ranges::views::transform([](auto x) { return x%2; });
}
int main() {
auto y = to_unordered_set(test());
return 0;
}
/*
/opt/compiler-explorer/gcc-11.3.0/include/c++/11.3.0/debug/safe_iterator.h:195:
In function:
__gnu_debug::_Safe_iterator<_Iterator, _Sequence,
_Category>::_Safe_iterator(__gnu_debug::_Safe_iterator<_Iterator,
_Sequence, _Category>&&) [with _Iterator =
__gnu_cxx::__normal_iterator<int*, std::__cxx1998::vector<int,
std::allocator<int> …Run Code Online (Sandbox Code Playgroud) 我正在尝试对笛卡尔积进行变换,最终使边缘变平。我收到的结果不是范围,这就是问题所在:
#include <ranges>
#include <vector>
#include <iostream>
#include <tuple>
#include <iterator>
int main() {
auto indicies = std::views::iota(0, 3);
auto coords = std::views::cartesian_product(indicies, indicies);
auto edges = coords | std::views::transform([](const auto& coord) {
using Coord = std::pair<std::size_t, std::size_t>;
using Edge = std::pair<Coord, Coord>;
std::vector<Edge> ret;
const auto& [x, y] = coord;
auto curr = Coord{x, y};
if (x + 1 < 3) {
auto dest = Coord{x + 1, y};
ret.emplace_back(curr, dest);
}
if (y + 1 < 3) { …Run Code Online (Sandbox Code Playgroud)