c++ - 如何声明接受转发引用并返回引用或拷贝的函数模板

标签 c++ c++14 perfect-forwarding

我正在尝试声明一个函数模板,它应该在传递左值时接受并返回非常量引用,但在传递右值时返回与 RVO 兼容的本地拷贝:

<template ?>
? StringReplace(? str, ? from, ? to);

我希望模板生成以下签名:

  1. 对于非常量左值

    std::string& StringReplace(std::string& str, const std::string& from, const std::string& to);
    
  2. 对于 const 左值

    std::string StringReplace(const std::string& str, const std::string& from, const std::string& to);
    
  3. 对于非常量右值

    std::string StringReplace(std::string&&, const std::string&, const std::string&)
    
  4. 对于常量右值

    std::string StringReplace(const std::string&&, const std::string&, const std::string&)
    
  5. 对于字符串文字

    std::string StringReplace(std::string&&, const std::string&, const std::string&)
    

是否可以使用单个模板指定一个? 也许标准库中有一个函数或方法可以通过使用一个或多个模板实现相同的结果我应该用作引用?


参见 my answer对于我最终得到的版本。

最佳答案

我相信这个基本想法符合您的要求:

template<typename Str>
Str foo(Str&& str)
{
    return std::forward<Str>(str);
}

如果参数是一个非常量左值,则 Str 被扣除为 S& 并且转发也解析为 S&

如果参数是右值,则 Str 被推导为 S,并且返回值是从参数复制/移动构造的。

如果您显式地给出模板参数,那么转发引用推导将被抑制,如果函数参数是 S& 的左值,您必须确保提供 S&可以直接绑定(bind)到;或者 S 否则。

通过引用传递的函数参数从不存在 RVO;例如假设调用上下文是 std::string s = StringReplace( std::string("foo"), x, Y); ,此时编译器无法知道使用相同的内存空间s 作为临时字符串。您能做的最好的事情就是移动构造返回值。


注意:您的原始代码尝试为所有 3 个参数推导 Str,这会导致推导冲突。您应该推导转发引用,对于其他两个,要么使用非推导上下文,要么使用不同的模板参数。例如:

template<typename Str, typename T>
Str StringReplace(Str&& str, T const& from, T const& to)

或使用 super 答案中所示的 CRef(如果参数出现在 :: 的左侧,则推导被禁用)。

关于c++ - 如何声明接受转发引用并返回引用或拷贝的函数模板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49331402/

相关文章:

c++ - VTBL 是否包含指向非虚函数的指针?

c++ - 如何使用 G++ 抑制纯虚拟类的 C++ vtable 生成?

c++ - 什么是 foo*(*)?

c++ - 从通用 lambda 调用 `this` 成员函数 - clang vs gcc

c++ - C++中简单可变参数函数的无与伦比的模板?

c++ - 在完美转发中 `decltype(std::forward<Args>(args))...` 和 Args&& 有什么区别

c++ - 完善的转运容器元素

模板的C++类成员访问问题

c++ - C++ 数组中的垃圾值是否可能为负数?

c++ - 重新排序可变参数