在 C++ 中按引用传递参数的默认值

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1059630/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 18:37:15  来源:igfitidea点击:

Default value to a parameter while passing by reference in C++

c++pass-by-referencedefault-value

提问by

Is it possible to give a default value to a parameter of a function while we are passing the parameter by reference. in C++

当我们通过引用传递参数时,是否可以为函数的参数提供默认值。在 C++ 中

For example, when I try to declare a function like:

例如,当我尝试声明一个函数时:

virtual const ULONG Write(ULONG &State = 0, bool sequence = true);

When I do this it gives an error:

当我这样做时,它会出现错误:

error C2440: 'default argument' : cannot convert from 'const int' to 'unsigned long &' A reference that is not to 'const' cannot be bound to a non-lvalue

错误 C2440:“默认参数”:无法从“const int”转换为“unsigned long &”非“const”的引用不能绑定到非左值

回答by

You can do it for a const reference, but not for a non-const one. This is because C++ does not allow a temporary (the default value in this case) to be bound to non-const reference.

您可以为常量引用执行此操作,但不能为非常量引用执行此操作。这是因为 C++ 不允许将临时值(在这种情况下为默认值)绑定到非常量引用。

One way round this would be to use an actual instance as the default:

解决此问题的一种方法是使用实​​际实例作为默认值:

static int AVAL = 1;

void f( int & x = AVAL ) {
   // stuff
} 

int main() {
     f();       // equivalent to f(AVAL);
}

but this is of very limited practical use.

但这在实际应用中非常有限。

回答by Richard Corden

It has been said in one of the direct comments to your answer already, but just to state it officially. What you want to use is an overload:

在对您的回答的直接评论之一中已经说过,但只是正式陈述。您要使用的是重载:

virtual const ULONG Write(ULONG &State, bool sequence);
inline const ULONG Write()
{
  ULONG state;
  bool sequence = true;
  Write (state, sequence);
}

Using function overloads also have additional benefits. Firstly you can default any argument you wish:

使用函数重载还有额外的好处。首先,您可以默认任何您希望的参数:

class A {}; 
class B {}; 
class C {};

void foo (A const &, B const &, C const &);
void foo (B const &, C const &); // A defaulted
void foo (A const &, C const &); // B defaulted
void foo (C const &); // A & B defaulted etc...

It is also possible to redefine default arguments to virtual functions in derived class, which overloading avoids:

还可以在派生类中为虚函数重新定义默认参数,这样重载避免了:

class Base {
public:
  virtual void f1 (int i = 0);  // default '0'

  virtual void f2 (int);
  inline void f2 () {
    f2(0);                      // equivalent to default of '0'
  }
};

class Derived : public Base{
public:
  virtual void f1 (int i = 10);  // default '10'

  using Base::f2;
  virtual void f2 (int);
};

void bar ()
{
  Derived d;
  Base & b (d);
  d.f1 ();   // '10' used
  b.f1 ();   // '0' used

  d.f2 ();   // f1(int) called with '0' 
  b.f2 ();   // f1(int) called with '0
}

There is only one situation where a default really needs to be used, and that is on a constructor. It is not possible to call one constructor from another, and so this technique does not work in that case.

只有一种情况确实需要使用默认值,那就是在构造函数上。不可能从另一个构造函数调用一个构造函数,因此这种技术在这种情况下不起作用。

回答by David Rodríguez - dribeas

There still is the old C way of providing optional arguments: a pointer that can be NULL when not present:

仍然有提供可选参数的旧 C 方式:一个指针,当不存在时可以为 NULL:

void write( int *optional = 0 ) {
    if (optional) *optional = 5;
}

回答by Mike Weir

This little template will help you:

这个小模板将帮助您:

template<typename T> class ByRef {
public:
    ByRef() {
    }

    ByRef(const T value) : mValue(value) {
    }

    operator T&() const {
        return((T&)mValue);
    }

private:
    T mValue;
};

Then you'll be able to:

然后你将能够:

virtual const ULONG Write(ULONG &State = ByRef<ULONG>(0), bool sequence = true);

回答by Max Lybbert

There are two reasons to pass an argument by reference: (1) for performance (in which case you want to pass by const reference) and (2) because you need the ability to change the value of the argument inside the function.

通过引用传递参数有两个原因:(1)为了性能(在这种情况下您希望通过常量引用传递)和(2)因为您需要能够更改函数内部参数的值。

I highly doubt that passing an unsigned long on modern architectures is slowing you down too much. So I'm assuming that you're intending to change the value of Stateinside the method. The compiler is complaining because the constant 0cannot be changed, as it's an rvalue ("non-lvalue" in the error message) and unchangeable (constin the error message).

我非常怀疑在现代架构上传递一个 unsigned long 会减慢你太多的速度。所以我假设您打算更改State方法内部的值。编译器抱怨是因为常量0无法更改,因为它是一个右值(错误消息中的“非左值”)并且不可更改(const错误消息中)。

Simply put, you want a method that can change the argument passed, but by default you want to pass an argument that can't change.

简单地说,你想要一个可以改变传递的参数的方法,但默认情况下你想要传递一个不能改变的参数。

To put it another way, non-constreferences have to refer to actual variables. The default value in the function signature (0) is not a real variable. You're running into the same problem as:

换句话说,非const引用必须引用实际变量。函数签名中的默认值 ( 0) 不是真正的变量。您遇到了与以下相同的问题:

struct Foo {
    virtual ULONG Write(ULONG& State, bool sequence = true);
};

Foo f;
ULONG s = 5;
f.Write(s); // perfectly OK, because s is a real variable
f.Write(0); // compiler error, 0 is not a real variable
            // if the value of 0 were changed in the function,
            // I would have no way to refer to the new value

If you don't actually intend to change Stateinside the method you can simply change it to a const ULONG&. But you're not going to get a big performance benefit from that, so I would recommend changing it to a non-reference ULONG. I notice that you are already returning a ULONG, and I have a sneaky suspicion that its value is the value of Stateafter any needed modifications. In which case I would simply declare the method as so:

如果您实际上并不打算State在方法内部进行更改,则只需将其更改为const ULONG&. 但是您不会从中获得很大的性能优势,因此我建议将其更改为 non-reference ULONG。我注意到您已经返回了 a ULONG,并且我偷偷地怀疑它的值是State任何需要修改后的值。在这种情况下,我会简单地将方法声明为:

// returns value of State
virtual ULONG Write(ULONG State = 0, bool sequence = true);

Of course, I'm not quite sure what you're writing or to where. But that's another question for another time.

当然,我不太确定你在写什么或写到哪里。但这是另一个问题。

回答by NascarEd

No, it's not possible.

不,这不可能。

Passing by reference implies that the function might change the value of the parameter. If the parameter is not provided by the caller and comes from the default constant, what is the function supposed to change?

通过引用传递意味着该函数可能会更改参数的值。如果参数不是由调用者提供的,而是来自默认常量,那么函数应该改变什么?

回答by deft_code

You cannot use a constant literal for a default parameter for the same reason you cannot use one as a parameter to the function call. Reference values must have an address, constant references values need not (ie they can be r-values or constant literals).

您不能将常量文字用作默认参数,原因与您不能将其用作函数调用的参数的原因相同。引用值必须有地址,常量引用值不需要(即它们可以是 r 值或常量文字)。

int* foo (int& i )
{
   return &i;
}

foo(0); // compiler error.

const int* bar ( const int& i )
{
   return &i;
}

bar(0); // ok.

Ensure that you're default value has an address and you're fine.

确保你的默认值有一个地址,你没问题。

int null_object = 0;

int Write(int &state = null_object, bool sequence = true)
{
   if( &state == &null_object )
   {
      // called with default paramter
      return sequence? 1: rand();
   }
   else
   {
      // called with user parameter
      state += sequence? 1: rand();
      return state;
   }
}

I've used this pattern a few times where I had a parameter that could be a variable or null. The regular approach is to have the user pass in a pointer this is case. They pass in a NULL pointer if they don't want you to fill in the value. I like to null object approach. It makes the callers life easier without terribly complicating the callee code.

我已经多次使用这种模式,其中我有一个可以是变量或空值的参数。在这种情况下,常规方法是让用户传入一个指针。如果他们不希望您填写该值,他们会传入一个 NULL 指针。我喜欢空对象方法。它使调用者的生活更轻松,而不会使被调用者代码非常复杂。

回答by ilya n.

I think not, and the reason is that default values are evaluated to constants and values passed by reference must be able to change, unless you also declare it to be constant reference.

我认为不是,原因是默认值被评估为常量,并且通过引用传递的值必须能够更改,除非您也将其声明为常量引用。

回答by JJTh

Another way could be the following:

另一种方法可能如下:

virtual const ULONG Write(ULONG &State, bool sequence = true);

// wrapper
const ULONG Write(bool sequence = true)
{
   ULONG dummy;
   return Write(dummy, sequence);
}

then the following calls are possible:

那么以下调用是可能的:

ULONG State;
object->Write(State, false); // sequence is false, "returns" State
object->Write(State); // assumes sequence = true, "returns" State
object->Write(false); // sequence is false, no "return"
object->Write(); // assumes sequence = true, no "return"

回答by Waxrat

void f(const double& v = *(double*) NULL)
{
  if (&v == NULL)
    cout << "default" << endl;
  else
    cout << "other " << v << endl;
}