2016-07-16 173 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

相关问题