std::forward 具有模板化重载函数

std::forward with templated overloaded function

我不知道为什么编译器会给我有关模板实例化的警告。

这是一段运行良好并正确输出 lvalue/rvalue 的代码:

//template<typename T>
void overloaded(const /*T*/std::string& in)
{
    std::cout << "lvalue" << std::endl;
}

//template<typename T>
void overloaded(/*T*/std::string&& in)
{
    std::cout << "rvalue" << std::endl;
}

template<typename T>
void pass(T&& in)
{
    overloaded(std::forward<T>(in));
}

int main()
{
    std::string a;
    pass(a);
    pass(std::move(a));
    getchar();
}

但我需要将它与模板化类型一起使用。所以将 "overloaded" 函数修改为

template<typename T>
void overloaded(const T& in)
{
    std::cout << "lvalue" << std::endl;
}

template<typename T>
void overloaded(T&& in)
{
    std::cout << "rvalue" << std::endl;
}

给出模板实例化警告,(对我来说它的明确 T 应该是 std::string),并且控制台输出右值 2 次而不是先输出左值。

我做错了什么?

T&&等模板比较特殊。他们被称为"forwarding references"。他们对以下函数有特殊的扣除规则:

template<typename T>
void overloaded(T&& in)

暂时假设 overloaded 没有超载。如果将 std::string 类型的左值表达式传递给 overloadedT 将推导为 std::string&。如果将 std::string 类型的右值表达式传递给 overloadedT 将推导为 std::string。您可以使用这些知识来做到这一点:

template<typename T>
void overloaded(T&& in)
{
    if (std::is_lvalue_reference<T>::value)
        std::cout << "lvalue" << std::endl;
    else
        std::cout << "rvalue" << std::endl;
}

一般来说,用其他任何东西重载 T&& 模板是一种反模式。当您想捕获所有内容时,这些特殊模板会派上用场。