我想编写一个函数identity
,它可以完美地转发它的参数而不需要任何副本。我会写这样的东西
template< typename V >
inline V&& identity( V&& v )
{
return std::forward< V >( v );
}
但这是对的吗?它总是返回正确的类型吗?如果它是左值/左值参考/临时,它是否只是简单地转发v
答案 0 :(得分:4)
您可以使用参数包作为警卫,这样任何人都不能实际强制使用与其他方式不同的类型。
作为一个最小的工作示例:
#include <type_traits>
#include <utility>
template<typename..., typename V>
constexpr V&& identity(V&& v) {
return std::forward<V>(v);
}
int main() {
static_assert(std::is_same<decltype(identity(42)), int&&>::value, "!");
static_assert(std::is_same<decltype(identity<int>(42)), int&&>::value, "!");
static_assert(std::is_same<decltype(identity<float>(42)), int&&>::value, "!");
// here is the example mentioned by @Jarod42 in the comments to the question
static_assert(std::is_same<decltype(identity<const int &>(42)), int&&>::value, "!");
}
这样,返回类型取决于v
参数的实际类型,并且您不能以任何方式强制副本。
如@bolov的评论所述,语法很快就会变得模糊不清 无论如何,正如@ Jarod42所建议的,这是一个关于我们正在做什么的更明确的问题。
举个例子:
template <typename... EmptyPack, typename V, typename = std::enable_if_t<sizeof...(EmptyPack) == 0>>
作为替代方案:
template <typename... EmptyPack, typename V, std::enable_if_t<sizeof...(EmptyPack) == 0>* = nullptr>
甚至:
template <typename... EmptyPack, typename V>
constexpr
std::enable_if_t<sizeof...(EmptyPack) == 0, V&&>
identity(V&& v) {
return std::forward<V>(v);
}
选择你喜欢的并使用它,在这种情况下它们应该都是有效的。