完美转发到作为参数接收的 lambda
Perfect forwarding to a lambda received as an argument
class Frame<P>
表示具有 P
类型像素的图像。由于底层数据缓冲区格式的多种灵活性,遍历其像素的算法并非易事。因此我想避免在 Frame<P>::iterate
.
中重复代码
template<typename P>
class Frame {
std::vector<P> buf;
public:
template<typename F>
void iterate(F f) const {
// iterate in a way that is performant for this buffer
// but here i use a simple iteration for demonstration
for(const P& p : buf){
for(int i=0; i<buf.size(); i++){
f(buf.data()[p]);
}
}
}
}
这允许(在 const Frame<P>& frame
上):
frame.iterate([](const P& p){ /* ... */ });
但我也想支持(在非常量上Frame<P>& frame
):
frame.iterate([](P& p){ /* ... */ });
std::move(frame).iterate([](P&& p){ /* ... */ });
有没有无需复制 iterate
中的代码的简单方法?
这与 有关,但还需要做更多的工作。简而言之,我们希望将 iterate
的 ref-qualified 版本转发到静态成员函数,该函数可以适当地转发 buf
的各个元素。这是一种方法:
template <typename P>
class Frame {
std::vector<P> buf;
template <typename F, typename Iter>
static void iterate_impl(F&& f, Iter first, Iter last) {
while (first != last) {
f(*first++);
}
}
public:
template <typename F>
void iterate(F f) const& {
iterate_impl(f, buf.begin(), buf.end());
}
template <typename F>
void iterate(F f) & {
iterate_impl(f, buf.begin(), buf.end());
}
template <typename F>
void iterate(F f) && {
iterate_impl(f,
std::make_move_iterator(buf.begin()),
std::make_move_iterator(buf.end()));
}
template <typename F>
void iterate(F f) const&& {
iterate_impl(f,
std::make_move_iterator(buf.begin()),
std::make_move_iterator(buf.end()));
}
};
另一种方法是使用 forward_like
函数:
template <typename T, typename U>
struct copy_cv_ref {
private:
using u_type = std::remove_cv_t<std::remove_reference_t<U>>;
using t_type_with_cv = std::remove_reference_t<T>;
template <bool condition, template <typename> class Q, typename V>
using apply_qualifier_if = std::conditional_t<condition,
Q<V>,
V
>;
static constexpr bool is_lvalue = std::is_lvalue_reference<T>::value;
static constexpr bool is_rvalue = std::is_rvalue_reference<T>::value;
static constexpr bool is_const = std::is_const<t_type_with_cv>::value;
static constexpr bool is_volatile = std::is_volatile<t_type_with_cv>::value;
public:
using type =
apply_qualifier_if<is_lvalue, std::add_lvalue_reference_t,
apply_qualifier_if<is_rvalue, std::add_rvalue_reference_t,
apply_qualifier_if<is_volatile, std::add_volatile_t,
apply_qualifier_if<is_const, std::add_const_t, u_type
>>>>;
};
template <typename T, typename U>
using copy_cvref_t = typename copy_cv_ref<T, U>::type;
template <typename Like, typename U>
constexpr decltype(auto) forward_like(U&& it) {
return static_cast<copy_cvref_t<Like&&, U&&>>(std::forward<U>(it));
}
然后您可以在 iterate_impl
的实施中使用它:
template <typename P>
class Frame {
std::vector<P> buf;
template <typename Self, typename F>
static void iterate_impl(Self&& self, F&& f) {
for (int i = 0; i < self.buf.size(); ++i) {
f(forward_like<Self>(self.buf[i]));
}
}
public:
template <typename F>
void iterate(F f) const& {
iterate_impl(*this, f);
}
template <typename F>
void iterate(F f) & {
iterate_impl(*this, f);
}
template <typename F>
void iterate(F f) && {
iterate_impl(std::move(*this), f);
}
template <typename F>
void iterate(F f) const&& {
iterate_impl(std::move(*this), f);
}
};
class Frame<P>
表示具有 P
类型像素的图像。由于底层数据缓冲区格式的多种灵活性,遍历其像素的算法并非易事。因此我想避免在 Frame<P>::iterate
.
template<typename P>
class Frame {
std::vector<P> buf;
public:
template<typename F>
void iterate(F f) const {
// iterate in a way that is performant for this buffer
// but here i use a simple iteration for demonstration
for(const P& p : buf){
for(int i=0; i<buf.size(); i++){
f(buf.data()[p]);
}
}
}
}
这允许(在 const Frame<P>& frame
上):
frame.iterate([](const P& p){ /* ... */ });
但我也想支持(在非常量上Frame<P>& frame
):
frame.iterate([](P& p){ /* ... */ });
std::move(frame).iterate([](P&& p){ /* ... */ });
有没有无需复制 iterate
中的代码的简单方法?
这与 iterate
的 ref-qualified 版本转发到静态成员函数,该函数可以适当地转发 buf
的各个元素。这是一种方法:
template <typename P>
class Frame {
std::vector<P> buf;
template <typename F, typename Iter>
static void iterate_impl(F&& f, Iter first, Iter last) {
while (first != last) {
f(*first++);
}
}
public:
template <typename F>
void iterate(F f) const& {
iterate_impl(f, buf.begin(), buf.end());
}
template <typename F>
void iterate(F f) & {
iterate_impl(f, buf.begin(), buf.end());
}
template <typename F>
void iterate(F f) && {
iterate_impl(f,
std::make_move_iterator(buf.begin()),
std::make_move_iterator(buf.end()));
}
template <typename F>
void iterate(F f) const&& {
iterate_impl(f,
std::make_move_iterator(buf.begin()),
std::make_move_iterator(buf.end()));
}
};
另一种方法是使用 forward_like
函数:
template <typename T, typename U>
struct copy_cv_ref {
private:
using u_type = std::remove_cv_t<std::remove_reference_t<U>>;
using t_type_with_cv = std::remove_reference_t<T>;
template <bool condition, template <typename> class Q, typename V>
using apply_qualifier_if = std::conditional_t<condition,
Q<V>,
V
>;
static constexpr bool is_lvalue = std::is_lvalue_reference<T>::value;
static constexpr bool is_rvalue = std::is_rvalue_reference<T>::value;
static constexpr bool is_const = std::is_const<t_type_with_cv>::value;
static constexpr bool is_volatile = std::is_volatile<t_type_with_cv>::value;
public:
using type =
apply_qualifier_if<is_lvalue, std::add_lvalue_reference_t,
apply_qualifier_if<is_rvalue, std::add_rvalue_reference_t,
apply_qualifier_if<is_volatile, std::add_volatile_t,
apply_qualifier_if<is_const, std::add_const_t, u_type
>>>>;
};
template <typename T, typename U>
using copy_cvref_t = typename copy_cv_ref<T, U>::type;
template <typename Like, typename U>
constexpr decltype(auto) forward_like(U&& it) {
return static_cast<copy_cvref_t<Like&&, U&&>>(std::forward<U>(it));
}
然后您可以在 iterate_impl
的实施中使用它:
template <typename P>
class Frame {
std::vector<P> buf;
template <typename Self, typename F>
static void iterate_impl(Self&& self, F&& f) {
for (int i = 0; i < self.buf.size(); ++i) {
f(forward_like<Self>(self.buf[i]));
}
}
public:
template <typename F>
void iterate(F f) const& {
iterate_impl(*this, f);
}
template <typename F>
void iterate(F f) & {
iterate_impl(*this, f);
}
template <typename F>
void iterate(F f) && {
iterate_impl(std::move(*this), f);
}
template <typename F>
void iterate(F f) const&& {
iterate_impl(std::move(*this), f);
}
};