The Author Online Book Forums are Moving

The Author Online Book Forums will soon redirect to Manning's liveBook and liveVideo. All book forum content will migrate to liveBook's discussion forum and all video forum content will migrate to liveVideo. Log in to liveBook or liveVideo with your Manning credentials to join the discussion!

Thank you for your engagement in the AoF over the years! We look forward to offering you a more enhanced forum experience.

40316 (14) [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 (104) [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.