如何将升压范围传递给接受any_range的函数

How to pass boost ranges to a function that accepts any_range

提问人:mecitsari 提问时间:3/30/2023 最后编辑:Benjamin Buchmecitsari 更新时间:3/30/2023 访问量:123

问:

我正在尝试编写一个类函数,该函数接受双随机访问范围。我的目的是能够将任何类型的范围传递给函数,该函数可以是 、 或 boost 范围。该代码适用于 和 ,但是当我尝试使用提升范围时,它会发出警告。boost::any_rangestd::vectorstd::dequestd::vectorstd::deque

我试过了这个:

#include <boost/range/irange.hpp>
#include <boost/range/adaptors.hpp>
#include <boost/range/any_range.hpp>
#include <iostream>
#include <iterator>
#include <vector>

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

struct Indexer {
    Indexer(const double param_) : param(param_) {}

    double operator()(const int i) const
    {
        return static_cast<double>(i) + param;
    }

private:
    const double param;
};

class Temp {
public:
    void workWithAnyRange(const Range& range) {
        workWithAnyRangeTemplated(range);
    }

private:
    template<typename R>
    void workWithAnyRangeTemplated(const R& r) {
        for (auto i : r) {
            std::cout << "i: " << i << std::endl;
        }
    }
};

int main() {
    Temp temp;

    temp.workWithAnyRange(std::vector<double>{1,2,3});
    temp.workWithAnyRange(std::deque<double>{1,2,3});
    temp.workWithAnyRange(boost::irange(0, 10) | boost::adaptors::transformed(Indexer(15.0))); //introduces the warning

    return 0;
}

我得到以下输出:

In file included from /opt/compiler-explorer/libs/boost_1_71_0/boost/range/detail/any_iterator.hpp:22:0,
                 from /opt/compiler-explorer/libs/boost_1_71_0/boost/range/any_range.hpp:17,
                 from <source>:5:
/opt/compiler-explorer/libs/boost_1_71_0/boost/range/detail/any_iterator_wrapper.hpp: In member function 'boost::range_detail::any_random_access_iterator_wrapper<WrappedIterator, Reference, Difference, Buffer>::reference boost::range_detail::any_random_access_iterator_wrapper<WrappedIterator, Reference, Difference, Buffer>::dereference() const [with WrappedIterator = boost::iterators::transform_iterator<boost::range_detail::default_constructible_unary_fn_wrapper<Indexer, double>, boost::range_detail::integer_iterator<int>, boost::use_default, boost::use_default>; Reference = double; Difference = long int; Buffer = boost::any_iterator_buffer<64ul>; boost::range_detail::any_random_access_iterator_wrapper<WrappedIterator, Reference, Difference, Buffer>::reference = double&]':
/opt/compiler-explorer/libs/boost_1_71_0/boost/range/detail/any_iterator_wrapper.hpp:510:57: warning: function returns address of local variable [-Wreturn-local-addr]
                 return dereference_cast<reference>(*m_it);
                                                         ^
/opt/compiler-explorer/libs/boost_1_71_0/boost/range/detail/any_iterator_wrapper.hpp:510:51: note: declared here
                 return dereference_cast<reference>(*m_it);
                                                   ^
ASM generation compiler returned: 0
In file included from /opt/compiler-explorer/libs/boost_1_71_0/boost/range/detail/any_iterator.hpp:22:0,
                 from /opt/compiler-explorer/libs/boost_1_71_0/boost/range/any_range.hpp:17,
                 from <source>:5:
/opt/compiler-explorer/libs/boost_1_71_0/boost/range/detail/any_iterator_wrapper.hpp: In member function 'boost::range_detail::any_random_access_iterator_wrapper<WrappedIterator, Reference, Difference, Buffer>::reference boost::range_detail::any_random_access_iterator_wrapper<WrappedIterator, Reference, Difference, Buffer>::dereference() const [with WrappedIterator = boost::iterators::transform_iterator<boost::range_detail::default_constructible_unary_fn_wrapper<Indexer, double>, boost::range_detail::integer_iterator<int>, boost::use_default, boost::use_default>; Reference = double; Difference = long int; Buffer = boost::any_iterator_buffer<64ul>; boost::range_detail::any_random_access_iterator_wrapper<WrappedIterator, Reference, Difference, Buffer>::reference = double&]':
/opt/compiler-explorer/libs/boost_1_71_0/boost/range/detail/any_iterator_wrapper.hpp:510:57: warning: function returns address of local variable [-Wreturn-local-addr]
                 return dereference_cast<reference>(*m_it);
                                                         ^
/opt/compiler-explorer/libs/boost_1_71_0/boost/range/detail/any_iterator_wrapper.hpp:510:51: note: declared here
                 return dereference_cast<reference>(*m_it);
                                                   ^
Execution build compiler returned: 0
Program returned: 0
i: 1
i: 2
i: 3
i: 1
i: 2
i: 3
i: 15
i: 16
i: 17
i: 18
i: 19
i: 20
i: 21
i: 22
i: 23
i: 24

如您所见,它输出了一些东西,但警告似乎令人担忧。如果我删除我调用函数的行,警告就会消失。谁能帮我解决这个问题?boost::irange

C++ 加速 提升范围

评论

0赞 Caleth 3/30/2023
您在哪个编译器和设置上看到该警告?这里没有警告
0赞 mecitsari 3/30/2023
我正在使用 gcc 5.4 和 -std=c++,如图所示
0赞 mecitsari 3/30/2023
我感觉我搞砸了编译器选项,因为这似乎有效

答:

3赞 sehe 3/30/2023 #1

我感觉我搞砸了编译器选项,因为这似乎有效—— 用户1508716 4分钟前

不,这只是因为它包含提升包含目录,而不是隐藏警告。-isystem-I

该警告指示转换的结果(右值)通过引用返回。相当令人惊讶,因为您要求引用类型为 .事实上,错误消息确认:double const

/opt/compiler-explorer/libs/boost_1_71_0/boost/range/detail/any_iterator_wrapper.hpp: In member function '
boost::range_detail::any_random_access_iterator_wrapper<WrappedIterator, Reference, Difference, Buffer>::reference boost::range_detail::any_random_access_iterator_wrapper<WrappedIterator, Reference, Difference, Buffer>::dereference()
const [with 
WrappedIterator = boost::iterators::transform_iterator<boost::range_detail::default_constructible_unary_fn_wrapper<Indexer, double>, boost::range_detail::integer_iterator<int>, boost::use_default, boost::use_default>;
Reference = double;
Difference = long int;
Buffer = boost::any_iterator_buffer<64ul>;
boost::range_detail::any_random_access_iterator_wrapper<WrappedIterator, Reference, Difference, Buffer>::reference = double&;
]':

请注意它如何按照您的要求确认这一点(顶级 const 在 C++ 中的函数签名中并不重要)。但是,它认为,使得不安全的实现:Reference = doubleboost::range_detail::any_random_access_iterator_wrapper<WrappedIterator, Reference, Difference, Buffer>::reference = double&dereference

virtual reference dereference() const
{
    return dereference_cast<reference>(*m_it);
}

与 Boost 1.81.0 相比没有问题:https://godbolt.org/z/9qfTzn15T

Indeed boost 1.74.0 包含一个修复程序:https://godbolt.org/z/vEe118f6G

事实上,boost 1.73.0 仍然存在问题:https://godbolt.org/z/EM56Pss5q

所涉及的变化似乎是

474efda Merge pull request #94 from mjendruk/fix-any-range-non-reference-references

哪些链接到 https://github.com/boostorg/range/pull/94“修复具有非参考引用的any_range可能导致 UB”

评论

0赞 mecitsari 3/30/2023
是否有任何解决方法可以克服此问题,因为不幸的是我无法更改升压版本?基本上,我需要一个可以预期双倍范围的函数,该函数应该支持随机访问
1赞 sehe 3/30/2023
这需要更好的框架。我想说的是,你不能十年不升级工具。您可以通过不键入擦除范围 () 来轻松做到这一点。或者你不能使用临时的 - 无论如何都需要缓冲,所以它们根本不会是性能的:godbolt.org/z/zEx87vPPKworkWithAnyRangeTemplated