你的函数接受一个右值引用,但你传递的是一个左值——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
完成后,现在如果您决定要支持集合右值,这很简单;以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
注意上面的实现只允许使用 exact matches 到Coll::value_type 的运算符,但允许任何可以转换为 Coll::value_type 的东西可能是明智的——实现这个,只需将std::is_same 替换为std::is_convertible。