40316 (11) [Avatar] Offline
#1
Hello,

If I could, I wanted to follow up on getting listing 1.5 working. I agree, as you state in chapter 1, that this is the perfect example so I just wanted to get it running in full.

I coded it up as follows:

#include "range/v3/all.hpp"
#include <fstream>
#include <algorithm>
#include <string>
#include <vector>
#include <iostream>

using namespace ranges::v3;

int count_lines(std::ifstream& in)
{
return std::count(std::istreambuf_iterator<char>(in),
std::istreambuf_iterator<char>(),
'\n');
}

std::ifstream open_file(const std::string& filename)
{
return std::move(std::ifstream(filename));
}

std::vector<int> count_lines_in_files(const std::vector<std::string>& files)
{
return files | view::transform(open_file) | view::transform(count_lines);
}

int main(int argc, char *argv[])
{
auto results = count_lines_in_files({"main.cpp", "Makefile", "test.txt"});

for (const auto &result: results) {
std::cout << result << " line(s)\n";
}

return 0;
}

I believe I have (count_lines: std::ifstream -> int) and (open_file: std::string -> std::ifstream)


but I get quite some error message:

g++ -std=c++17 -I/home/default/ranges/range-v3-master/include -fexceptions main2.cpp -o mainit2
main2.cpp: In function ‘std::vector<int> count_lines_in_files(const std::vector<std::basic_string<char> >&)’:
main2.cpp:24:45: error: could not convert ‘ranges::v3::operator|<ranges::v3::transform_view<ranges::v3::iterator_range<__gnu_cxx::__normal_iterator<const std::basic_string<char>*, std::vector<std::basic_string<char> > >, __gnu_cxx::__normal_iterator<const std::basic_string<char>*, std::vector<std::basic_string<char> > > >, std::basic_ifstream<char> (*)(const std::basic_string<char>&)>, ranges::v3::view::view<ranges::v3::detail::pipeable_binder<std::_Bind<ranges::v3::view::transform_fn(std::_Placeholder<1>, int (*)(std::basic_ifstream<char>&))> > >, false, 0u>(ranges::v3::operator|<const std::vector<std::basic_string<char> >&, ranges::v3::view::view<ranges::v3::detail::pipeable_binder<std::_Bind<ranges::v3::view::transform_fn(std::_Placeholder<1>, std::basic_ifstream<char> (*)(const std::basic_string<char>&))> > >, false, 0u>((* & files), ranges::v3::view::view<View>::operator()(Ts&& ...) const [with Ts = {std::basic_ifstream<char, std::char_traits<char> > (&)(const std::basic_string<char, std::char_traits<char>, std::allocator<char> >&)}; V = ranges::v3::view::transform_fn; View = ranges::v3::view::transform_fn; decltype (ranges::v3::view::{anonymous}::make_view(ranges::v3::view::view_access::impl<V>::bind(((const ranges::v3::view::view<View>*)this)->ranges::v3::view::view<View>::view_, static_cast<Ts&>(ranges::v3::view::view::operator()::ts) ...))) = ranges::v3::view::view<ranges::v3::detail::pipeable_binder<std::_Bind<ranges::v3::view::transform_fn(std::_Placeholder<1>, std::basic_ifstream<char> (*)(const std::basic_string<char>&))> > >](open_file)), ranges::v3::view::view<View>::operator()(Ts&& ...) const [with Ts = {int (&)(std::basic_ifstream<char, std::char_traits<char> >&)}; V = ranges::v3::view::transform_fn; View = ranges::v3::view::transform_fn; decltype (ranges::v3::view::{anonymous}::make_view(ranges::v3::view::view_access::impl<V>::bind(((const ranges::v3::view::view<View>*)this)->ranges::v3::view::view<View>::view_, static_cast<Ts&>(ranges::v3::view::view::operator()::ts) ...))) = ranges::v3::view::view<ranges::v3::detail::pipeable_binder<std::_Bind<ranges::v3::view::transform_fn(std::_Placeholder<1>, int (*)(std::basic_ifstream<char>&))> > >](count_lines))’ from ‘void’ to ‘std::vector<int>’
return files | view::transform(open_file) | view::transform(count_lines);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /home/default/ranges/range-v3-master/include/range/v3/utility/copy.hpp:18:0,
from /home/default/ranges/range-v3-master/include/range/v3/begin_end.hpp:24,
from /home/default/ranges/range-v3-master/include/range/v3/core.hpp:17,
from /home/default/ranges/range-v3-master/include/range/v3/all.hpp:17,
from main2.cpp:1:
/home/default/ranges/range-v3-master/include/range/v3/view/view.hpp: In instantiation of ‘static void ranges::v3::view::view<View>::pipe(Rng&&, Vw&&) [with Rng = ranges::v3::transform_view<ranges::v3::iterator_range<__gnu_cxx::__normal_iterator<const std::basic_string<char>*, std::vector<std::basic_string<char> > >, __gnu_cxx::__normal_iterator<const std::basic_string<char>*, std::vector<std::basic_string<char> > > >, std::basic_ifstream<char> (*)(const std::basic_string<char>&)>; Vw = ranges::v3::view::view<ranges::v3::detail::pipeable_binder<std::_Bind<ranges::v3::view::transform_fn(std::_Placeholder<1>, int (*)(std::basic_ifstream<char>&))> > >&; bool _concept_requires_118 = false; typename std::enable_if<(_concept_requires_118 || (! typename meta::v1::defer<meta::v1::detail::_and_<false>::invoke, typename meta::v1::defer<meta::v1::detail::_and_<false>::invoke, ranges::v3::concepts::models<ranges::v3::concepts::Range, Container>, typename meta::v1::defer<meta::v1::detail::_or_<false>::invoke, std::is_lvalue_reference<Rng>, ranges::v3::concepts::models<ranges::v3::concepts::View, typename std::remove_cv<typename std::remove_reference<_SrcTuple>::type>::type> >::type>::type, ranges::v3::concepts::models<ranges::v3::concepts::Invocable, Action&, Rng> >::type()))>::type* <anonymous> = 0u; View = ranges::v3::detail::pipeable_binder<std::_Bind<ranges::v3::view::transform_fn(std::_Placeholder<1>, int (*)(std::basic_ifstream<char>&))> >]’:
/home/default/ranges/range-v3-master/include/range/v3/utility/functional.hpp:729:9: required from ‘decltype (ranges::v3::pipeable_access::impl<Pipe>::pipe(static_cast<Arg&&>(arg), pipe)) ranges::v3::operator|(Arg&&, Pipe) [with Arg = ranges::v3::transform_view<ranges::v3::iterator_range<__gnu_cxx::__normal_iterator<const std::basic_string<char>*, std::vector<std::basic_string<char> > >, __gnu_cxx::__normal_iterator<const std::basic_string<char>*, std::vector<std::basic_string<char> > > >, std::basic_ifstream<char> (*)(const std::basic_string<char>&)>; Pipe = ranges::v3::view::view<ranges::v3::detail::pipeable_binder<std::_Bind<ranges::v3::view::transform_fn(std::_Placeholder<1>, int (*)(std::basic_ifstream<char>&))> > >; bool _concept_requires_727 = false; typename std::enable_if<(_concept_requires_727 || ((! ranges::v3::is_pipeable<T>()) && ranges::v3::is_pipeable<Pipe>()))>::type* <anonymous> = 0u; decltype (ranges::v3::pipeable_access::impl<Pipe>::pipe(static_cast<Arg&&>(arg), pipe)) = void]’
main2.cpp:24:74: required from here
/home/default/ranges/range-v3-master/include/range/v3/utility/concepts.hpp:699:28: error: static assertion failed: This view is not callable with this range type.
#define CONCEPT_ASSERT_MSG static_assert
^
/home/default/ranges/range-v3-master/include/range/v3/view/view.hpp:125:21: note: in expansion of macro ‘CONCEPT_ASSERT_MSG’
CONCEPT_ASSERT_MSG(Invocable<View&, Rng>(),


just wondering if there is something simple I am doing wrong?
Ivan Cukic (99) [Avatar] Offline
#2
You need to get ifstream as a rvalue reference in count_lines or to get it by value.

int count_lines(std::ifstream&& in)                                                                  
{                                                                               
    return std::count(std::istreambuf_iterator<char>(in),                       
            std::istreambuf_iterator<char>(),                                   
             '\n');                                                              
}


This way, the temporary created by open_file can be moved into the next transformation.

This is always advised: value, a const-ref or a rvalue ref.