如何通过引用同一个模板函数来传递一行boost::multi_array和std::vector?

问题描述 投票:0回答:2

我对这段代码有疑问:

#include <boost/multi_array.hpp>
#include <boost/array.hpp>
#include <vector>
#include <iostream>

template <typename Vec>
void foo(Vec& x, size_t N)
{
    for (size_t i = 0; i < N; ++i) {
        x[i] = i;
    }
}

int main()
{
    std::vector<double> v1(10);
    foo(v1, 5);
    std::cout << v1[4] << std::endl;


    boost::multi_array<double, 2> m1;
    boost::array<double, 2> shape;
    shape[0] = 10;
    shape[1] = 10;
    m1.resize(shape);
    foo(m1[0], 5);
    std::cout << m1[0][4] << std::endl;
    return 0;
}

尝试用 gcc 编译它,我收到错误:

boost_multi_array.cpp: In function 'int main()':
boost_multi_array.cpp:26: error: invalid initialization of non-const reference of type 'boost::detail::multi_array::sub_array<double, 1u>&' from a temporary of type 'boost::detail::multi_array::sub_array<double, 1u>'
boost_multi_array.cpp:7: error: in passing argument 1 of 'void foo(Vec&, size_t) [with Vec = boost::detail::multi_array::sub_array<double, 1u>]'

当我将函数

foo
的第一个参数的类型从
Vec&
更改为
Vec
时,它按 boost::multi_array 的预期工作,但随后 std::vector 按值传递,这不是我想要的想。不写两个模板如何实现我的目标?

c++ templates boost boost-multi-array
2个回答
1
投票

问题是,对于 NumDims > 1

operator[]
返回类型为
template subarray<NumDims-1>::type
的临时对象。

一个(不太好的)解决方法如下:

typedef boost::multi_array<double, 2> MA;
MA m1;
MA::reference ref = m1[0];
foo(ref, 5); // ref is no temporary now

另一种方法是包装您的实现并为多数组情况提供重载......例如:

(注意:我没有看到如何让重载与

boost::multi_array<T,N>::reference
一起工作,请不要将其与此
detail::
版本一起投入生产;)

template<class T>
void foo_impl(T x, size_t N) {
    for (size_t i = 0; i < N; ++i) {
        x[i] = i;
    }
}

template<class T>
void foo(T& t, size_t n) {
    foo_impl<T&>(t, n);
}

template<typename T, size_t size>
void foo(boost::detail::multi_array::sub_array<T, size> r, size_t n) {
    foo_impl(r, n);
}

0
投票

解决方案应该很简单,通用参考:

template <typename Vec>
void foo(Vec&& x, size_t N)
{
    for (size_t i = 0; i < N; ++i) {
        x[i] = i;
    }
}

既然你已经做到了,让实现更加正确(向前),返回一些有用的东西,并命名它:

template <typename Vec>
void iota_first_n(Vec&& x, size_t N)
{
   auto const last = x.begin() + N;
   std::iota(std::forward<Vec>(x).begin(), last, std::size_t{0});
   return last;
}
© www.soinside.com 2019 - 2024. All rights reserved.