你的函數接受一個右值引用,但你傳遞一個左 - Left<T, Alloc>&&
是不轉發引用,所以與std::forward
等把它當作這樣是不正確的。現在,我們將禁止收集右值把事情簡單化:
template<
typename T,
typename Alloc,
template<typename, typename> class Left
>
Left<T, Alloc>& operator <<(Left<T, Alloc>& coll, T&& value) {
coll.push_back(std::forward<T>(value));
return coll;
}
以上是更近了一步,但如果will not work傳遞的左值的value
。一種選擇是強制正確的論據Left
:
template<
typename T,
typename Alloc,
template<typename, typename> class Left
>
Left<typename std::decay<T>::type, Alloc>&
operator <<(Left<typename std::decay<T>::type, Alloc>& coll, T&& value) {
coll.push_back(std::forward<T>(value));
return coll;
}
Online Demo
這工作,但不會離開我們的任何簡單的方法來支持收集右值。正確的解決方法這裏IMO是停止使用模板,模板,要麼static_assert
,容器的value_type
比賽T
或SFINAE運營商的路程,如果它不:
template<typename Coll, typename T>
Coll& operator <<(Coll& coll, T&& value) {
static_assert(std::is_same<
typename std::decay<T>::type,
typename Coll::value_type
>::value,
"T does not match Coll::value_type"
);
coll.push_back(std::forward<T>(value));
return coll;
}
Online Demo
或
template<typename Coll, typename T>
typename std::enable_if<std::is_same<
typename std::decay<T>::type,
typename Coll::value_type
>::value,
Coll&
>::type
operator <<(Coll& coll, T&& value) {
coll.push_back(std::forward<T>(value));
return coll;
}
Online Demo
完成這一工作後,現在如果您決定要支持收集rvalues,那麼這樣做很簡單;使用static_assert
實施爲例:
template<typename Coll, typename T>
Coll&& operator <<(Coll&& coll, T&& value) {
static_assert(std::is_same<
typename std::decay<T>::type,
typename std::decay<Coll>::type::value_type
>::value,
"T does not match Coll::value_type"
);
coll.push_back(std::forward<T>(value));
return std::forward<Coll>(coll);
}
Online Demo
N.B.上面的實現只允許使用具有完全匹配到Coll::value_type
運營商,但它可能是明智的,允許任何可以轉換爲Coll::value_type
- 要實現這一點,只是std::is_convertible
取代std::is_same
。
爲什麼會留下<...> &&不是轉發參考? (爲什麼它不被認爲是一種類型推斷的情況?) – kfsone
@kfsone:該標準將轉發引用定義爲「對cv-非限定模板參數的右值引用」;一個專門的模板參數與模板參數不一樣。 : - ] – ildjarn
感謝您的解釋。我可以看到這是一個常見的誤解 – kfsone