共享const lvalue(const T&)和rvalue(T&&)重载的实现:就像对const和非const重载所做的那样

时间:2015-03-30 12:38:41

标签: c++ c++11 rvalue-reference rvalue pass-by-rvalue-reference

背景

以下代码块出现在Scott Meyers的着名书籍"Effective C++"第3项:

class TextBlock {
public:
    ...
    const char& operator[](std::size_t position) const
    {
        ...    // do bounds checking
        ...    // log access data
        ...    // verify data integrity
        return text[position];
    }
    char& operator[](std::size_t position)
    {
        ...    // do bounds checking
        ...    // log access data
        ...    // verify data integrity
        return text[position];
    }
    ...
private:
    std::string text;
};

作者指出,在上面的实现中,const和非const重载的内容基本相同。为了避免代码重复,它可以简化为:

class TextBlock {
public:
    ...
    const char& operator[](std::size_t position) const    // the same as before
    {
        ...
        ...
        ...
        return text[position];
    }
    char& operator[](std::size_t position)        // now just calls const op[]
    {
        return                                    // cast away const on
          const_cast<char&>(                      // op[]'s return type;
            static_cast<const TextBlock&>(*this)  // add const to *this's type;
              [position]                          // call const version of op[]
          );
    }
    ...
private:
    std::string text;
};

问题

我的问题是:

  • 我们何时需要const T&的重载和T&&的重载? (这里,T可能是模板参数或类类型,因此T&&可能是也可能不是通用引用。我可以看到,在标准库中,许多类都提供了重载。例子是std::pairstd::tuple的构造函数,有大量的重载。 (好的,我知道在这些函数中,其中一个是复制构造函数,其中一个是移动构造函数。)

  • 是否有类似的技巧来分享const T&T&&重载的实现?我的意思是,如果const T&&重载返回一个复制构造的对象,并且T&&重载返回一些移动构造的东西,在共享实现之后,该属性仍然必须保持。 (就像上面的技巧一样:const返回const而非 - const返回非const,无论是在实现共享之前还是之后)

谢谢!

澄清

我指的两个重载应该是这样的:

Gadget f(Widget const& w);
Gadget f(Widget&& w);

与rvalue引用返回无关,即:

Widget&& g(/* ... */);

(顺便说一下,这个问题在my previous post

中得到了解决

在上面的f()中,如果Gadget是可复制构造和可移动构造的,那么除了阅读实现之外没有办法告诉返回值是复制构造还是移动 - 建造。没有什么可以处理返回值优化(RVO)/命名返回值优化(NRVO)。 (见my previous post

参考

Effective C++

std::pair::pair

std::tuple::tuple

When is it a good time to return by rvalue references?

1 个答案:

答案 0 :(得分:2)

  

•我们什么时候需要为const T&amp; amp;另一个用于T&amp;&amp;?

基本上,当移动为你带来性能提升时,应该还有一个移动构造函数。这同样适用于您需要昂贵副本的功能。

在您的示例中,如果您返回对char的引用,则建议不要设置返回右值引用的函数。相反,按价值返回并依赖编译器应用RVO的能力(参见例如here

  

•是否有类似的技巧来分享const T&amp; amp;的实现?和T&amp;&amp;重载?

我经常发现使用通用引用(我懒惰)设置构造函数或函数很有用,例如

struct MyClass
{
    template<typename T /*, here possibly use SFINAE to allow only for certain types */>
    MyClass(T&& _t) : t(std::forward<T>(_t)) {}
private:
    SomeType t;
};

编辑:关于您的更新:如果您的函数Widget中有f的昂贵副本,则建议过载{{1} }}

Widget&&

你可以使用像这样的函数模板组合这两个函数

Gadget f(Widget const& w)
{
    Widget temp = w;  //expensive copy
}
Gadget f(Widget&& w)
{
    Widget temp = std::move(w);  //move
}

......我没有说它更好; - )。


编辑2 :另请参阅this thread,它可以更加充分地解决您的问题。