我有一个应根据用户提供的谓词过滤其内容的类。给我的接口规定了对谓词的引用:
class Test {
vector<int> data;
public:
template <class PREDTYPE>
void filter(PREDTYPE& pred) {
return;
}
};
我还得到了一段测试代码,看起来像这样:
class Filter {
public:
bool operator()(int) const {
return false;
}
};
int main() {
Test test;
test.filter(Filter());
}
这不会编译,说cannot bind non-const lvalue reference of type 'Filter&' to an rvalue of type 'Filter'
。如果我将测试代码更改为
int main() {
Test test;
Filter filter;
test.filter(filter);
}
它可以工作,但这取决于最终用户,我无法控制他们的行为。我尝试重载filter方法,创建了一个版本,该版本将按值接受谓词,然后按引用传递给它,但这两者都不会编译,并显示消息call of overloaded 'filter(Filter&)' is ambiguous
。
因此,我的问题是:是否有可能构造一个既可以接受谓词的rvalue又可以接受lvalue的过滤器?
答案 0 :(得分:4)
简而言之,是(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!
}
这将接受rvalue和lvalues,而不必依赖const
-引用(因此,您的谓词仍然是可变的)。如果您坚持使用较旧的C ++标准,则最好的选择是改用const引用(上面强调了警告)或将过滤器嵌入std::function
中,并依靠调用站点的隐式转换。>
答案 1 :(得分:2)
这取决于函数对谓词的作用。如果它在返回后仍保留了对它的引用/指针,则您必须提供可以长期使用的东西。但是,如果它不保留传入的谓词对象的任何内存,则可以将谓词转换为左值:
test.filter(static_cast<Filter&>(Filter()));
或将其转换为简短的实用函数:
template <class T>
T& stay(T&& a)
{ return a; }
test.filter(stay(Filter()));
答案 2 :(得分:1)
您可能希望将成员函数签名更改为
template <class PREDTYPE> void filter(PREDTYPE&& pred)
在此,谓词作为通用引用传递,对于在传入的rvalue的右值引用中传递的左值,折叠为左值引用。
答案 3 :(得分:0)