c++ 如何将boost范围传递给接受any_range的函数

3mpgtkmj  于 2023-04-01  发布在  其他
关注(0)|答案(1)|浏览(122)

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

#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调用函数的那一行,警告就会消失。有人能帮助我解决这个问题吗?

b1zrtrql

b1zrtrql1#

我有一种感觉,我搞砸了与编译器选项,因为这似乎是它的作品-user 1508716 4分钟前
不,这只是因为它包含了boost include目录,其中包含了-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&;
]':

注意它是如何按照你的要求确认Reference = double的(顶级const在C++中的函数签名中并不重要)。然而,它认为boost::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
实际上,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“Fix any_range with non-reference references can cause UB”的链接

相关问题