I have a simplified analogue of netgen in C++. In one pipeline, I need to output to a file the coordinates of those nodes (as a container std::array of three elements) that fall inside a sphere of a given radius and with a given center. It is required to output lists from 10 to 20 in this set. To implement the solution, I decided to use Ranges from C++20. The problem is that I can't output the filtered nodes to a file. Here is a part of my code
#include "AneuMeshLoader.h" #include "MeshExceptions.h" #include "Strukturs.h" #include <array> #include <cmath> #include <fstream> #include <iostream> #include <memory> #include <ranges> #include <string> using namespace std; ostream &operator<<(ostream &os, const array<double, 3> &vec) { os << "{ "; bool first = true; for (const auto &elem : vec) { os << (first ? "" : ", ") << elem; first = false; } return os << " }"; } bool isWithinSphere(const Node &node, const array<double, 3> ¢er, double radius) { double dx = node.x - center[0]; double dy = node.y - center[1]; double dz = node.z - center[2]; return (dx * dx + dy * dy + dz * dz) <= (radius * radius); } int main(int argc, char *argv[]) { string mesh_file = (argc > 1) ? argv[1] : "MeshExample.aneu"; try { unique_ptr<MeshLoader> loader = make_unique<AneuMeshLoader>(); Mesh mesh = loader->loadMesh(mesh_file); array<double, 3> sphere_center = {0.0, 0.0, 0.0}; double radius = 10.0; std::ofstream output("filtered_nodes.txt"); if (!output.is_open()) { std::cerr << "Failed to open output file." << std::endl; return 1; } // Pipeline auto filtered_nodes = mesh.getNodes() | ranges::views::filter([&](const Node &node) { return node.isVertex && isWithinSphere(node, sphere_center, radius); }) | ranges::views::transform( [](const Node &node) { return node.coords(); }) | ranges::views::drop(10) | ranges::views::take(10); ranges::copy(filtered_nodes.begin(), filtered_nodes.end(), ostream_iterator<array<double, 3>>(output, " ")); // ERROR!!!! output.close(); cout << "Filtered nodes have been written to the file." << endl; Here is the implementation getNodes from filtered_nodes:
const std::vector<Node> &Mesh::getNodes() const { return nodes; } Here is the console output when compiling:
In file included from /usr/include/c++/14.2.1/iterator:65, from /usr/include/c++/14.2.1/ranges:43, from Main.cpp:9: /usr/include/c++/14.2.1/bits/stream_iterator.h: In the specification «std::ostream_iterator<_Tp, _CharT, _Traits>& std::ostream_iterator<_Tp, _CharT, _Traits>::operator=(const _Tp&) [с _Tp = std::array<double, 3>; _CharT = char; _Traits = std::char_traits<char>]»: /usr/include/c++/14.2.1/bits/ranges_algobase.h:287:13: requires from «constexpr std::__conditional_t<_IsMove, std::ranges::in_out_result<_Iter, _Out>, std::ranges::in_out_result<_Iter, _Out> > std::ranges::__copy_or_move(_Iter, _Sent, _Out) [с bool _IsMove = false; _Iter = std::counted_iterator<transform_view<filter_view<ref_view<const std::vector<Node> >, main(int, char**)::<lambda(const Node&)> >, main(int, char**)::<lambda(const Node&)> >::_Iterator<false> >; _Sent = take_view<drop_view<transform_view<filter_view<ref_view<const std::vector<Node> >, main(int, char**)::<lambda(const Node&)> >, main(int, char**)::<lambda(const Node&)> > > >::_Sentinel<false>; _Out = std::ostream_iterator<std::array<double, 3> >; std::__conditional_t<_IsMove, in_out_result<_Iter, _Out>, in_out_result<_Iter, _Out> > = in_out_result<std::counted_iterator<transform_view<filter_view<ref_view<const std::vector<Node> >, main(int, char**)::<lambda(const Node&)> >, main(int, char**)::<lambda(const Node&)> >::_Iterator<false> >, std::ostream_iterator<std::array<double, 3> > >]» 287 | *__result = *__first; | ~~~~~~~~~~^~~~~~~~~~ /usr/include/c++/14.2.1/bits/ranges_algobase.h:303:38: requires from «constexpr std::ranges::copy_result<_Iter, _Out> std::ranges::__copy_fn::operator()(_Iter, _Sent, _Out) const [с _Iter = std::counted_iterator<std::ranges::transform_view<std::ranges::filter_view<std::ranges::ref_view<const std::vector<Node> >, main(int, char**)::<lambda(const Node&)> >, main(int, char**)::<lambda(const Node&)> >::_Iterator<false> >; _Sent = std::ranges::take_view<std::ranges::drop_view<std::ranges::transform_view<std::ranges::filter_view<std::ranges::ref_view<const std::vector<Node> >, main(int, char**)::<lambda(const Node&)> >, main(int, char**)::<lambda(const Node&)> > > >::_Sentinel<false>; _Out = std::ostream_iterator<std::array<double, 3> >; std::ranges::copy_result<_Iter, _Out> = std::ranges::in_out_result<std::counted_iterator<std::ranges::transform_view<std::ranges::filter_view<std::ranges::ref_view<const std::vector<Node> >, main(int, char**)::<lambda(const Node&)> >, main(int, char**)::<lambda(const Node&)> >::_Iterator<false> >, std::ostream_iterator<std::array<double, 3> > >]» 303 | return ranges::__copy_or_move<false>(std::move(__first), | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~ 304 | std::move(__last), | ~~~~~~~~~~~~~~~~~~ 305 | std::move(__result)); | ~~~~~~~~~~~~~~~~~~~~ Main.cpp:56:17: required from here 56 | ranges::copy(filtered_nodes.begin(), filtered_nodes.end(), | ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 57 | ostream_iterator<array<double, 3>>(output, " "));
std::array<double,3>when you mean a 3d vector. Make a struct for that. It will make your code 1) more readable, 2) semantically more clear (you prevent your overloads triggering for arrays with 3 values that are not vectors)operator<<is not found by name lookup. The lookup is performed from inside namespacestd(namely, from the implementation ofstd::ostream_iterator), and there are plenty of overloads ofoperator<<there, so ordinary lookup finds them and stops looking; the global namespace is never searched. Nor is your overload found by argument-dependent lookup, since all its parameters are also in namespacestd.stdstd::arraydoesn't have iostream support. You need to useviews::jointo flatten your view; theniostream_iterator<double>is available.ranges::copydoesn't need iterator pair; it's better to pass the view itself. If you need formatted output, you can use a range basedforto insert EOL(\n), or usestd::format_to(iff C++23std::range_formatteris available).