C++ 将函数对象作为左值和/或右值传递

mac*_*inn 4 c++ templates function-object

我有一个类应该根据用户提供的谓词过滤其内容。我给出的接口规定引用谓词:

\n\n
class Test {\n  vector<int> data;\npublic:\n  template <class PREDTYPE>\n  void filter(PREDTYPE& pred) {\n    return;\n  }\n};\n
Run Code Online (Sandbox Code Playgroud)\n\n

我还得到了一段测试代码,大致如下:

\n\n
class Filter {\npublic:\n  bool operator()(int) const {\n    return false;\n  }\n};\n\nint main() {\n  Test test;\n  test.filter(Filter());\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

这不会\xe2\x80\x99t 编译,说cannot bind non-const lvalue reference of type 'Filter&' to an rvalue of type 'Filter'。如果我将测试代码更改为

\n\n
int main() {\n  Test test;\n  Filter filter;\n  test.filter(filter);\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

它有效,但这取决于最终用户,我无法控制他们的行为。我尝试重载过滤器方法,创建一个版本,该版本将按值接受谓词,然后通过引用传递它,但这也不会\xe2\x80\x99t编译,并显示消息call of overloaded 'filter(Filter&)' is ambiguous

\n\n

因此我的问题是:是否可以构造一个同时接受谓词的右值和左值的过滤器?

\n

Rer*_*ito 5

简而言之,是的(C++11)

您只需依靠参考折叠规则来确保这一点:

template <typename PREDTYPE>
void filter(PREDTYPE&& pred) { // notice the &&
    // ... Whatever
    // Use perfect forwarding *IF* you can
    std::forward<PREDTYPE>(pred)(some_stuff);
    // Do not use pred after it has been forwarded!
}
Run Code Online (Sandbox Code Playgroud)

这将接受右值和左值,而不必依赖const- 引用(因此您的谓词仍然可以是可变的)。如果您坚持使用较旧的 C++ 标准,最好的办法是使用 const 引用(上面突出显示了警告)或将过滤器嵌入到 an 中std::function并依赖于调用站点的隐式转换。