Произвольный доступ к boost::transformed_range через boost::any_range

Я пытаюсь использовать boost::any_range (с тегом произвольного доступа) в каком-то устаревшем коде, но обнаружил, что он не любит лямбды. Ошибка компиляции, кажется, жалуется на отсутствие конструктора по умолчанию для лямбда-объектов. Это ожидаемое поведение? Это по дизайну? Я нахожусь на MSVC C++17 с буст-версией 1.66.

В документации упоминается, что transmed_range имеет ту же категорию, что и диапазон ввода:

https://www.boost.org/doc/libs/1_66_0/libs/range/doc/html/range/reference/adaptors/reference/transformed.html

Проблема, очевидно, где-то в boost::any_rangeпотому что, если я просто использую авто, это работает (ср rngneg_auto ниже)

#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/any_range.hpp>
#include <iostream>
#include <vector>

using boost::adaptors::transformed;

using double_range = boost::any_range<const double
                                      , boost::random_access_traversal_tag
                                      , const double>;

struct negate
{
    constexpr double operator() (const double x) const
    {
        return -x;
    }
};

int main(int argc, char** argv) 
{
    const std::vector<double> v{ 1.0, 2.0, 3.0 };

    // this works
    const auto rngneg_auto = v | transformed([](double x) { return -x; });
    std::cout << "Second element is " << rngneg_auto[1] << std::endl;

    // ... and this
    const double_range rngneg = v | transformed(negate());
    std::cout << "Second element is " << rngneg[1] << std::endl;

#if 0
    // but not that
    const double_range rngneg_lambda = v | transformed([](double x) { return -x; });
    std::cout << "Second element is " << rngneg_lambda[1] << std::endl;
#endif

    return 0;
}

Для первых двух случаев программа печатает

Second element is -2
Second element is -2

В-третьих, это ошибка компиляции (я думаю, это потому, что лямбды не могут быть построены по умолчанию):

1>\boost.org\boost\1.66.0\include\boost\optional\optional.hpp(733): error C2280: 'main::<lambda_6f21fa0f6ab2ea01b2b99a85be3eab65> &main::<lambda_6f21fa0f6ab2ea01b2b99a85be3eab65>::operator =(const main::<lambda_6f21fa0f6ab2ea01b2b99a85be3eab65> &)': attempting to reference a deleted function
1> ***: note: see declaration of 'main::<lambda_6f21fa0f6ab2ea01b2b99a85be3eab65>::operator ='
1>\boost.org\boost\1.66.0\include\boost\optional\optional.hpp(733): note: while compiling class template member function 'void boost::optional_detail::optional_base<T>::assign_value(main::<lambda_6f21fa0f6ab2ea01b2b99a85be3eab65> &&)'
1>        with
1>        [
1>            T=main::<lambda_6f21fa0f6ab2ea01b2b99a85be3eab65>
1>        ]
1>\boost.org\boost\1.66.0\include\boost\optional\optional.hpp(262): note: see reference to function template instantiation 'void boost::optional_detail::optional_base<T>::assign_value(main::<lambda_6f21fa0f6ab2ea01b2b99a85be3eab65> &&)' being compiled
1>        with
1>        [
1>            T=main::<lambda_6f21fa0f6ab2ea01b2b99a85be3eab65>
1>        ]
1>\boost.org\boost\1.66.0\include\boost\optional\optional.hpp(831): note: see reference to class template instantiation 'boost::optional_detail::optional_base<T>' being compiled
1>        with
1>        [
1>            T=main::<lambda_6f21fa0f6ab2ea01b2b99a85be3eab65>
1>        ]
1>\boost.org\boost\1.66.0\include\boost\range\detail\default_constructible_unary_fn.hpp(48): note: see reference to class template instantiation 'boost::optional<F>' being compiled
1>        with
1>        [
1>            F=main::<lambda_6f21fa0f6ab2ea01b2b99a85be3eab65>
1>        ]
1>\boost.org\boost\1.66.0\include\boost\utility\detail\result_of_iterate.hpp(70): note: see reference to class template instantiation 'boost::range_detail::default_constructible_unary_fn_wrapper<F,R>' being compiled
1>        with
1>        [
1>            F=main::<lambda_6f21fa0f6ab2ea01b2b99a85be3eab65>,
1>            R=double
1>        ]
1>\boost.org\boost\1.66.0\include\boost\utility\detail\result_of_iterate.hpp(43): note: see reference to class template instantiation 'boost::detail::cpp0x_result_of<F (T0)>' being compiled
1>        with
1>        [
1>            F=const boost::range_detail::default_constructible_unary_fn_wrapper<main::<lambda_6f21fa0f6ab2ea01b2b99a85be3eab65>,double> &,
1>            T0=const double &
1>        ]
1>\boost.org\boost\1.66.0\include\boost\mpl\eval_if.hpp(41): note: see reference to class template instantiation 'boost::result_of<const UnaryFunc &(const double &)>' being compiled
1>        with
1>        [
1>            UnaryFunc=boost::range_detail::default_constructible_unary_fn_wrapper<main::<lambda_6f21fa0f6ab2ea01b2b99a85be3eab65>,double>
1>        ]
1>\boost.org\boost\1.66.0\include\boost\iterator\iterator_adaptor.hpp(154): note: see reference to class template instantiation 'boost::mpl::eval_if<boost::is_same<T,boost::iterators::use_default>,DefaultNullaryFn,boost::mpl::identity<T>>' being compiled
1>        with
1>        [
1>            T=boost::iterators::use_default,
1>            DefaultNullaryFn=boost::result_of<const boost::range_detail::default_constructible_unary_fn_wrapper<main::<lambda_6f21fa0f6ab2ea01b2b99a85be3eab65>,double> &(const double &)>
1>        ]
1>\boost.org\boost\1.66.0\include\boost\iterator\transform_iterator.hpp(55): note: see reference to class template instantiation 'boost::iterators::detail::ia_dflt_help<Reference,boost::result_of<const UnaryFunc &(const double &)>>' being compiled
1>        with
1>        [
1>            Reference=boost::iterators::use_default,
1>            UnaryFunc=boost::range_detail::default_constructible_unary_fn_wrapper<main::<lambda_6f21fa0f6ab2ea01b2b99a85be3eab65>,double>
1>        ]
1>\boost.org\boost\1.66.0\include\boost\iterator\transform_iterator.hpp(81): note: see reference to class template instantiation 'boost::iterators::detail::transform_iterator_base<UnaryFunc,Iterator,Reference,Value>' being compiled
1>        with
1>        [
1>            UnaryFunc=boost::range_detail::default_constructible_unary_fn_wrapper<main::<lambda_6f21fa0f6ab2ea01b2b99a85be3eab65>,double>,
1>            Iterator=std::_Vector_const_iterator<std::_Vector_val<std::_Simple_types<double>>>,
1>            Reference=boost::iterators::use_default,
1>            Value=boost::iterators::use_default
1>        ]
1>c:\program files (x86)\microsoft visual studio\2017\professional\vc\tools\msvc\14.14.26428\include\xutility(652): note: see reference to class template instantiation 'boost::iterators::transform_iterator<boost::range_detail::default_constructible_unary_fn_wrapper<F,R>,It,boost::iterators::use_default,boost::iterators::use_default>' being compiled
1>        with
1>        [
1>            F=main::<lambda_6f21fa0f6ab2ea01b2b99a85be3eab65>,
1>            R=double,
1>            It=std::_Vector_const_iterator<std::_Vector_val<std::_Simple_types<double>>>
1>        ]
1>\boost.org\boost\1.66.0\include\boost\iterator\iterator_categories.hpp(120): note: see reference to class template instantiation 'std::iterator_traits<Iterator>' being compiled
1>        with
1>        [
1>            Iterator=boost::iterators::transform_iterator<boost::range_detail::default_constructible_unary_fn_wrapper<main::<lambda_6f21fa0f6ab2ea01b2b99a85be3eab65>,double>,std::_Vector_const_iterator<std::_Vector_val<std::_Simple_types<double>>>,boost::iterators::use_default,boost::iterators::use_default>
1>        ]
1>\boost.org\boost\1.66.0\include\boost\range\iterator_range_core.hpp(156): note: see reference to class template instantiation 'boost::iterators::iterator_traversal<IteratorT>' being compiled
1>        with
1>        [
1>            IteratorT=boost::iterators::transform_iterator<boost::range_detail::default_constructible_unary_fn_wrapper<main::<lambda_6f21fa0f6ab2ea01b2b99a85be3eab65>,double>,std::_Vector_const_iterator<std::_Vector_val<std::_Simple_types<double>>>,boost::iterators::use_default,boost::iterators::use_default>
1>        ]
1>\boost.org\boost\1.66.0\include\boost\range\iterator_range_core.hpp(436): note: see reference to class template instantiation 'boost::iterator_range_detail::pure_iterator_traversal<IteratorT>' being compiled
1>        with
1>        [
1>            IteratorT=boost::iterators::transform_iterator<boost::range_detail::default_constructible_unary_fn_wrapper<main::<lambda_6f21fa0f6ab2ea01b2b99a85be3eab65>,double>,std::_Vector_const_iterator<std::_Vector_val<std::_Simple_types<double>>>,boost::iterators::use_default,boost::iterators::use_default>
1>        ]
1>\boost.org\boost\1.66.0\include\boost\range\adaptor\transformed.hpp(44): note: see reference to class template instantiation 'boost::iterator_range<boost::iterators::transform_iterator<boost::range_detail::default_constructible_unary_fn_wrapper<F,R>,It,boost::iterators::use_default,boost::iterators::use_default>>' being compiled
1>        with
1>        [
1>            F=main::<lambda_6f21fa0f6ab2ea01b2b99a85be3eab65>,
1>            R=double,
1>            It=std::_Vector_const_iterator<std::_Vector_val<std::_Simple_types<double>>>
1>        ]
1>***: note: see reference to class template instantiation 'boost::range_detail::transformed_range<main::<lambda_6f21fa0f6ab2ea01b2b99a85be3eab65>,const std::vector<double,std::allocator<_Ty>>>' being compiled
1>        with
1>        [
1>            _Ty=double
1>        ]
1>***: note: 'main::<lambda_6f21fa0f6ab2ea01b2b99a85be3eab65> &main::<lambda_6f21fa0f6ab2ea01b2b99a85be3eab65>::operator =(const main::<lambda_6f21fa0f6ab2ea01b2b99a85be3eab65> &)': function was explicitly deleted

1 ответ

Он задыхается, потому что пытается выяснить, как создать any_range из transformed_range, и думает, что лямбда - это конструируемый тип по умолчанию. Я не стал вдаваться в подробности, почему, но я представляю, что это потому, что нет ничего, что прямо говорит, что это не так, и тип лямбды уникален. Конечно, бессмысленно пытаться создать лямбда-тип по умолчанию.

Я бы сказал, что самый простой способ заставить его работать - это использовать тип, в котором ясно (через стандартные шаблоны), что он не может быть создан по умолчанию, то есть std::function<>. Это компилирует:

const double_range rngneg_lambda = v | transformed(static_cast<std::function<double(double)>>([](double x) { return -x; }));
Другие вопросы по тегам