你的函数接受一个右值引用,但你传递一个左 - 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