访问顺序序列元素的通用方法

时间:2014-02-05 14:06:49

标签: c++ generics multidimensional-array

编写用于定位C数组,C ++库和C ++标准库的通用代码的最佳方法是什么?

示例:点积

template<class Vector1, class Vector2>
constexpr auto dot_product(Vector1 const& v1, Vector2 const& v2) {
  // doesn't work for Vectors that do not implement () subscripting
  using return_type = decltype(v1(0) + v2(0)); 
  return_type tmp = return_type{};
  // doesn't work for e.g. std::tuple
  for (std::size_t i = 0, e = size(v1); i != e; ++i) {
    tmp += v1(i) * v2(i);
  }
  return tmp;
}
  • 访问元素时出现问题:

    • 表示C数组array[i],C矩阵array[i][j]
    • 获取C ++ std::vectorvector[i]
    • 获取C ++ tuplestd::get<i>(tuple)
    • 对于C ++线性代数向量/矩阵(例如Eigen):vector(i)matrix(i, j)
  • 迭代存在问题:

    • C数组循环的运行时,std::vectors,...
    • boost::fusion例如std::arraystd::tuple,...
    • 线性代数库的自定义表达式,可以处理两种情况(例如Eigen使用表达式模板)
  • Boost.Geometry使用get函数来解决访问问题,从而导致代码完整无处不在get。它还使用策略来调度不同的迭代方法。

还有更好的选择吗?

2 个答案:

答案 0 :(得分:1)

您可以使用基于策略的模板。

template <typename T> 
struct DefaultUsePolicy {
    int DoSomethingWithT( T const & ) {
        return 42;
    }
};
template < typename T, typename UsePolicy = DefaultUsePolicy<T>>
int Generic( T& arg ) {
    UsePolicy use;
    return use.DoSomethingWithT(arg);
}

然后有一些普通类型的默认实现,如果用户有自定义类型,请让用户编写策略。

通用功能将在其所需的策略中记录服务需求。

std::unique_ptrstd::default_deleter类似,可以控制对所拥有指针的破坏。

答案 1 :(得分:1)

您可以将get函数包装在类中,例如:

#define Return(ret) decltype ret { return ret; }

template <typename T>
class Getter
{
private:
    T& t;
public:
    constexpr explicit Getter(T&t) : t(t) {}

    constexpr auto operator () (std::size_t i) const
    -> Return((get(t, i)))

    constexpr auto operator () (std::size_t i, std::size_t j) const
    -> Return((get(t, i, j)))

    operator T&() const { return t; }
};

template <typename T>
Getter<T> make_getter(T&t) { return Getter<T>(t); }

然后

template<class Vector1, class Vector2>
constexpr auto dot_product(Vector1 const& v1_arg, Vector2 const& v2_arg) {
  auto v1 = make_getter(v1_arg);
  auto v2 = make_getter(v2_arg);
  using return_type = decltype(v1(0) + v2(0)); 
  return_type tmp = return_type{};
  for (std::size_t i = 0, e = size(v1); i != e; ++i) {
      tmp += v1(i) * v2(i);
  }
  return tmp;
}