实现函数模板填充多维对象

Implement function template to fill multi-dimensional objects

在 C++ 中填充多维对象(数组、嵌套标准容器等)一直让我很烦。通常使用嵌套循环。例如,要用值 v 填充 3 维对象 obj,您可以这样写

for (auto& x : obj) {
  for (auto& y : x) {
    for (auto& z : y) {
      z = v;
    }
  }
}

这样的循环是代码噪音,写起来很乏味,也妨碍代码阅读。我正在考虑编写一个函数模板来执行填充。理想情况下,有了这样的函数模板,你应该可以写出类似

的东西
fill(obj, v);

有什么想法吗?

目前,我有一个功能模板make_multi()来制作多维对象。所以你可以做

// assuming `obj` is a 3x3x3 nested `std::vector`
obj = make_multi<std::vector>(v, 3, 3, 3);

除了代码比理想情况更多之外,此解决方案还是性能噩梦。最终,我必须寻找更好的方法。

你可以写一个扁平化的foreach:

namespace detail {
    template <typename Range, typename Func>
    constexpr auto flat_foreach(Range&& r, Func& f, int)
        -> decltype(void(f(std::forward<Range>(r)))) {f(std::forward<Range>(r));}

    template <typename Range, typename Func>
    constexpr void flat_foreach(Range&& r, Func& f...) {
        for (auto&& i : r)
            flat_foreach(std::forward<decltype(i)>(i), f, 0);
    }
}

template <typename Range, typename Func>
constexpr void flat_foreach(Range&& r, Func f) 
{detail::flat_foreach(std::forward<Range>(r), f, 0);}

Demo。这是 non-greedy 方法,将范围传递给尽可能浅的给定函数。

这是 的贪婪对应:

namespace detail {
    using std::begin;
    using std::end;

    template<typename Elem, typename Func>
    constexpr void flat_foreach(Elem&& e, Func& f, long) {
        f(std::forward<Elem>(e));
    }

    template<typename Range, typename Func>
    constexpr auto flat_foreach(Range&& r, Func& f, int)
      -> decltype(begin(r), void(end(r))) {
        for (auto&& i : r) {
            flat_foreach(std::forward<decltype(i)>(i), f, 0);
        }
    }
}

template<typename Range, typename Func>
constexpr void flat_foreach(Range&& r, Func f) {
    detail::flat_foreach(std::forward<Range>(r), f, 0);
}

Online Demo

这种方法的一般优点是可以为 f.

传入一个 generic lambda/functor