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

标签 c++ c++11 constants code-duplication

这是 this question 的一个特例其中 that answer不直接工作。

Consider :

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' solution 的精神,我想出了以下内容:

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));
    });
}    

但是,这似乎比它的值(value)更麻烦,尤其是当类型很长并且我不能使用 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。这并不总是很重要,因为您通常不希望成员函数在右值上被调用。我将在此处添加它,因为我认为它是更通用解决方案的一部分。

不幸的是,*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 是类模板的情况下,这减少了编译器必须处理的函数模板的数量(每个类模板一个,而不是每个实例一个)。不过,这通常需要一些样板代码和前向声明。
  • 您可以以自由函数或成员函数的形式调用具有相同名称的函数,例如furg f; for_each_hurg(furg, [](hurg){}); furg.for_each_hurg([](hurg){}); (当非限定查找找到成员函数时,它不执行/忽略 ADL 的结果。因此,您必须将 friend 函数放在命名空间范围,以便能够通过非静态成员函数包装器中的限定 ID 引用它。)

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

关于c++ - 如何避免将类成员传递给回调的类似 const 和非 const 成员函数之间的代码重复?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31839035/

相关文章:

c++在线程之间共享状态的最佳方式

c++ - 何时在 C++14 中使用变量 odr?

c++双重检查是否带锁的语句优化

c - 如何使用 C 中先前定义的常量来定义静态常量?

c++ - 如何避免到处链接某个目标文件

c++ - 分支中的 Lambda 未采用常量表达式 : Who is right?

c++ - 为什么不能默认模板模板参数?

c++ - 为什么有的引用类型的变量可以绑定(bind)右值,有的不能?

c++ - uintX_t 和 intX_t 类型的打印保证

c++ - 可以为了速度牺牲常量正确性吗?