完美转发的身份功能

Mar*_*ese 4 c++ forwarding c++11

我想编写一个函数identity,它可以完美地转发其参数而无需任何副本。我会写这样的东西

 template< typename V >
 inline V&& identity( V&& v )
 {
   return std::forward< V >( v );
 }
Run Code Online (Sandbox Code Playgroud)

但这是正确的吗?它是否总是返回正确的类型?v如果它是左值/左值引用/临时,它是否简单地独立转发?

sky*_*ack 5

您可以使用参数包作为保护,这样就没有人可以实际强制使用与否则会推导出的类型不同的类型。
作为最小的工作示例:

#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, "!");
}
Run Code Online (Sandbox Code Playgroud)

这样,返回类型取决于v参数的实际类型,您不能以任何方式强制复制。


正如@bolov 的评论中提到的,语法很快就会变得晦涩难懂。
无论如何,正如@Jarod42 所建议的,这是对我们正在做的事情更加明确的问题。

举个例子:

template <typename... EmptyPack, typename V, typename = std::enable_if_t<sizeof...(EmptyPack) == 0>>
Run Code Online (Sandbox Code Playgroud)

作为备选:

template <typename... EmptyPack, typename V, std::enable_if_t<sizeof...(EmptyPack) == 0>* = nullptr>
Run Code Online (Sandbox Code Playgroud)

甚至:

template <typename... EmptyPack, typename V>
constexpr
std::enable_if_t<sizeof...(EmptyPack) == 0, V&&>
identity(V&& v) {
    return std::forward<V>(v);
}
Run Code Online (Sandbox Code Playgroud)

选择您喜欢的一个并使用它,在这种情况下它们应该都是有效的。