[英]C++ Passing function objects as lvalues and/or rvalues
我有一個類應該根據用戶提供的謂詞過濾其內容。 我得到的接口規定了對謂詞的引用:
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
的消息call of overloaded 'filter(Filter&)' is ambiguous
。
因此我的問題是:是否有可能構造一個過濾器來接受謂詞的右值和左值?
簡而言之,是的(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!
}
這將接受右值和左值,而不必依賴const
- 引用(因此您的謂詞仍然可以是可變的)。 如果您堅持使用較舊的 C++ 標准,最好的辦法是改用 const 引用(上面突出顯示了警告)或將過濾器嵌入std::function
並依賴調用站點的隱式轉換。
這取決於函數對謂詞的作用。 如果它在返回后保留指向它的引用/指針,則您必須提供一些可以存活足夠長的東西。 但是,如果它沒有保留傳入的謂詞對象的任何內存,則可以將謂詞轉換為左值:
test.filter(static_cast<Filter&>(Filter()));
或者將其包裝在一個簡短的實用函數中:
template <class T>
T& stay(T&& a)
{ return a; }
test.filter(stay(Filter()));
您可能希望將成員函數簽名更改為
template <class PREDTYPE> void filter(PREDTYPE&& pred)
在這里,謂詞作為轉發引用傳遞,對於傳入的左值,它會折疊為左值引用,而右值引用則是對傳入的右值的引用。
通常,函數對象應該按值傳遞。 所以不要超載並將您的簽名更改為
template <class PREDTYPE> void filter(PREDTYPE pred)
可以在此處找到為什么這更好的解釋。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.