1

标题说明了一切。

第一种情况 f(const X&) 是老式的 const 引用参数。

但是,当采用可变引用参数时,为什么不总是使用 X&& 呢?这样,客户端代码可以使用临时值或常规左值,而不是 f() 指示用法。

编辑:我的草率,对不起。我的意思是,给定 fc(const X&) 和 fm(X&&),我们需要 fm(X&) 吗?

编辑:示例:我使用无状态装饰器作为参数传递:

class Base64Writer: public Writer {
public:
  Base64Writer(Writer& w): w_(w) {}
private:
  virtual void doWrite() override;
  Writer& w_;
}

void func(Writer&& w) { w.doWrite(); }

// to be called as
Writer wr = ...;
func(Base64Writer(wr));
4

3 回答 3

2
  • 如果您要问:同时拥有所有三个重载是否合乎逻辑?

    在大多数情况下,这将是一个坏主意。因为重载函数的语义相互矛盾。一个承诺它不会修改论点,另一个不会做出任何这样的承诺(它默认说它会修改论点!)。这种重载函数的用户会感到困惑,只有const.

    同时拥有这些重载是有意义的:

    void process(std::vector<int> const&);
    void process(std::vector<int> &&);
    

    但是除了上述两个之外,第三个对我来说没有多大意义:

    void process(std::vector<int> &); //contradicts the first overload
    

    它只会增加混乱并使代码更难阅读。如果您想要这种语义,请为函数选择不同的名称!

  • 如果您要问:您应该拥有哪一个(尽管不一定同时拥有)?

    我会说,这取决于语义。如果参数表现为输入和/或输出参数,则f(X&)有意义。如果参数只是输入参数,那么f(X const&)是有意义的,在这种情况下你也可以额外定义f(X&&),以获得性能优势!

于 2013-01-19T09:17:43.340 回答
2

绝对地!

例如,每当您操作作为参数传递的容器时,您都需要它。

事实上,您可能需要所有这三个 - 比较这些,例如:

vector<int> append_if_not_ends_with(vector<int> const &original, int x)
{
    vector<int> v(original);
    if (v.empty() || v.back() != x)
    { v.push_back(x); }
    return v;
}

vector<int> &append_if_not_ends_with(vector<int> &v, int x)
{
    if (v.empty() || v.back() != x)
    { v.push_back(x); }
    return v;
}

vector<int> append_if_not_ends_with(vector<int> &&original, int x)
{
    vector<int> v(std::move(original));
    if (v.empty() || v.back() != x)
    { v.push_back(x); }
    return v;
}

如果您拥有所有 3 个重载,那么您可以避免在不需要时复制向量的内容。

vector<int> v1;
vector<int> const &v2 =
    foo ? append_if_not_ends_with(v1) :
    bar ? append_if_not_ends_with(static_cast<vector<int> const &>(v1)) :
          append_if_not_ends_with(vector<int>());
于 2013-01-19T09:21:12.220 回答
1

令我惊讶的是,没有人指出您实际上可以按值传递,并且 c++11 中的这种做法实际上是您认为需要时做的正确事情f(X&&)

海事组织:

  • f(const X &)如果您只需要从元素中读取,请使用。
  • f(X)如果您需要获取传递的对象的所有权,请使用。您的函数的调用者可以在适当的时候执行f( std::move(something))f(something)执行。
  • f(X&)如果您需要修改传递的对象,请使用。
于 2013-01-19T10:38:11.923 回答