![](/img/trans.png)
[英]What is this template “specialization” code doing, and why does it compile but not work as expected?
[英]Why does template template parameters not work as expected?
#include <vector>
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 std::forward<Left<T, Alloc>>(coll);
}
using namespace std;
int main()
{
vector<int> c1;
c1 << int(8);
}
VS 2015的輸出:
錯誤C2678:二進制'<<':未找到采用'std :: vector>類型的左手操作數的運算符(或沒有可接受的轉換)
為什么模板模板參數不能按預期工作?
您的函數接受一個右值引用,但是您傳遞了一個左值-Left Left<T, Alloc>&&
不是轉發引用,因此用std::forward
等將其視為不正確。 現在,我們將禁止使用集合rvalue來簡化事情:
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;
}
上面的步驟更近了一步,但如果為value
傳遞了左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;
}
這行得通,但並沒有給我們提供支持集合右值的任何簡便方法。 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;
}
要么
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;
}
完成此操作后,現在如果您決定要支持集合右值,那么這很簡單。 以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);
}
注意,上述實現只允許使用與 Coll::value_type
完全匹配的運算符,但允許將任何可轉換為 Coll::value_type
內容合理地實現–實施此方法,只需將std::is_same
替換為std::is_convertible
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.