2016-07-16 95 views
0
#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 ::矢量>'(或沒有可接受的轉化率)

爲什麼模板模板參數不能按預期工作?

回答

6

你的函數接受一個右值引用,但你傳遞一個左 - 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

+0

爲什麼會留下<...> &&不是轉發參考? (爲什麼它不被認爲是一種類型推斷的情況?) – kfsone

+1

@kfsone:該標準將轉發引用定義爲「對cv-非限定模板參數的右值引用」;一個專門的模板參數與模板參數不一樣。 : - ] – ildjarn

+0

感謝您的解釋。我可以看到這是一個常見的誤解 – kfsone

相關問題