繁体   English   中英

如何避免将类成员传递给回调的类似const和非const成员函数之间的代码重复?

[英]How to avoid code duplication between similar const and non-const member functions which pass class members to callbacks?

这是该问题的特定情况, 答案不能直接起作用。

考虑

struct hurg {};

class furg {
public:
    template <class F>
    void for_each_hurg(F&& f) const {
        for (auto& h : hurgs) {
            f(h);
        }
    }

    template <class F>
    void for_each_hurg(F&& f) {
        for (auto& h : hurgs) {
            f(h);
        }
    }
private:
    std::vector<hurg> hurgs;
};

用法:

furg f;
const auto& cf = f;

f.for_each_hurg([](hurg& h) { });
cf.for_each_hurg([](const hurg& h) { });

对于该代码const和非const版本是相同的,但这仅仅是因为auto& h推断const hurg&在所述第一壳体和hurg&在第二种情况下。

本着先前与Scott Meyers解决方案相关联的精神,我提出了以下建议:

template <class F>
void for_each_hurg(F&& f) {
    const_cast<const furg&>(*this).for_each_hurg([&f](const hurg& h) {
        f(const_cast<hurg&>(h));
    });
}    

但是,这似乎比它的价值还要麻烦,尤其是当类型很长并且如果我不能使用C ++ 14的通用lambda时。

您可以使用静态成员函数模板将*this转发到通用函数参数:

template<typename Self, typename F>
static void for_each_hurg(Self& s, F&& f) {
    for (auto& h : s.hurgs) {
        f(h);
    }
}

template<typename F>
void for_each_hurg(F&& f) { for_each_hurg(*this, forward<F>(f))); }

template<typename F>
void for_each_hurg(F&& f) const { for_each_hurg(*this, forward<F>(f))); }

由于成员函数的引用限定符的出现,一般的解决方案是完美地转发*this 这并不总是很重要,因为您通常不希望在rvalues上调用成员函数。 我将其添加到此处,因为我认为它是更通用解决方案的一部分。

不幸的是, *this始终是一个左值,因此您需要在成员函数包装器中进行其他手动维护:

template<typename Self, typename F>
static void for_each_hurg(Self&& s, F&& f) {
    /* ... */
}

template<typename F>
void for_each_hurg(F&& f) && { for_each_hurg(move(*this), forward<F>(f))); }

template<typename F>
void for_each_hurg(F&& f) & { for_each_hurg(*this, forward<F>(f))); }

不幸的是,这不是对称的:(


也可以通过好友功能模板来实现上述功能。 这可以有两个好处:

  • 您可以将furg Function模板移到名称空间范围,这在furg是类模板的情况下减少了编译器必须处理的功能模板的数量(每个类模板一个,而不是每个实例化一个)。 但是,这通常需要一些样板代码和前向声明。
  • 您可以使用相同名称的函数作为自由函数或成员函数,例如furg f; for_each_hurg(furg, [](hurg){}); furg.for_each_hurg([](hurg){}); furg f; for_each_hurg(furg, [](hurg){}); furg.for_each_hurg([](hurg){}); (当非限定查找找到一个成员函数时,它不会执行/忽略ADL的结果。因此,您必须将Friendly函数放入命名空间范围内,以便能够通过限定ID引用它从非静态成员函数包装器中)。

此外,您还必须保护该功能模板免于贪婪。 通过将其放入某些namespace detail或添加enable-if子句。 这可能不值得付出努力。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM