태그 보관물: pass-by-reference

pass-by-reference

C ++에서 참조로 전달하는 동안 매개 변수에 대한 기본값 bool sequence = true); 이렇게하면 오류가 발생합니다.

참조로 매개 변수를 전달하는 동안 함수의 매개 변수에 기본값을 제공 할 수 있습니까? C ++에서

예를 들어 다음과 같은 함수를 선언하려고 할 때 :

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

이렇게하면 오류가 발생합니다.

오류 C2440 : ‘기본 인수’: ‘const int’에서 ‘unsigned long &’로 변환 할 수 없습니다. ‘const’가 아닌 참조는 lvalue가 아닌 값에 바인딩 할 수 없습니다.



답변

const 참조에 대해서는 할 수 있지만 const가 아닌 참조에는 할 수 없습니다. 이는 C ++에서 임시 (이 경우 기본값)가 상수가 아닌 참조에 바인딩되는 것을 허용하지 않기 때문입니다.

한 가지 방법은 실제 인스턴스를 기본값으로 사용하는 것입니다.

static int AVAL = 1;

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

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

그러나 이것은 매우 제한된 실제 사용입니다.


답변

이미 귀하의 답변에 대한 직접적인 의견 중 하나에서 언급되었지만 공식적으로 언급했습니다. 사용하려는 것은 과부하입니다.

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

함수 오버로드를 사용하면 추가 이점도 있습니다. 먼저 원하는 인수를 기본값으로 설정할 수 있습니다.

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...

파생 클래스의 가상 함수에 대한 기본 인수를 재정의 할 수도 있습니다. 이렇게하면 오버로딩이 방지됩니다.

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
}

기본값을 실제로 사용해야하는 상황은 하나 뿐이며 생성자에 있습니다. 한 생성자를 다른 생성자에서 호출 할 수 없으므로이 기술은이 경우 작동하지 않습니다.


답변

선택적 인수를 제공하는 이전 C 방식이 여전히 있습니다. 존재하지 않을 때 NULL 일 수있는 포인터 :

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


답변

이 작은 템플릿은 다음과 같은 이점을 제공합니다.

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

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

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

private:
    T mValue;
};

그러면 다음을 수행 할 수 있습니다.

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


답변

아니요, 불가능합니다.

참조로 전달하면 함수가 매개 변수 값을 변경할 수 있음을 의미합니다. 매개 변수가 호출자에 의해 제공되지 않고 기본 상수에서 오는 경우 변경해야하는 함수는 무엇입니까?


답변

참조로 인수를 전달하는 데는 두 가지 이유가 있습니다. (1) 성능 (이 경우 const 참조로 전달하려는 경우)과 (2) 함수 내에서 인수 값을 변경할 수있는 기능이 필요하기 때문입니다.

나는 현대 건축에 서명되지 않은 장기를 전달하는 것이 당신을 너무 느리게 만드는 것이라고 매우 의심합니다. 그래서 나는 당신이 State메소드 내부의 값을 변경하려고한다고 가정합니다 . 컴파일러는 상수 0가 rvalue (오류 메시지에서 “non-lvalue”)이고 변경할 수 없기 때문에 (오류 메시지에서) 변경할 수 없기 때문에 불평하고 있습니다 const.

간단히 말해, 전달 된 인수를 변경할 수있는 메서드를 원하지만 기본적으로 변경할 수없는 인수를 전달하려고합니다.

달리 말하면 비 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

State메서드 내에서 실제로 변경하지 않으려 는 경우 간단히 const ULONG&. 그러나 당신은 그것으로부터 큰 성능 이점을 얻지 못할 것이므로 비 참조로 변경하는 것이 좋습니다 ULONG. 나는 당신이 이미를 반환하고 ULONG있음을 알고 있으며 그 값이 State필요한 수정 후의 값이라는 은밀한 의심을 가지고 있습니다 . 어떤 경우에는 간단하게 메서드를 다음과 같이 선언합니다.

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

물론, 나는 당신이 무엇을 쓰고 있는지, 어디에 있는지 잘 모르겠습니다. 그러나 그것은 또 다른 질문입니다.


답변

함수 호출에 대한 매개 변수로 사용할 수없는 것과 같은 이유로 기본 매개 변수에 상수 리터럴을 사용할 수 없습니다. 참조 값에는 주소가 있어야하며 상수 참조 값은 필요하지 않습니다 (즉, r 값 또는 상수 리터럴 일 수 있음).

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

foo(0); // compiler error.

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

bar(0); // ok.

기본 값에 주소가 있고 괜찮은지 확인하십시오.

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;
   }
}

이 패턴은 변수 나 null이 될 수있는 매개 변수가있는 곳에서 몇 번 사용했습니다. 일반적인 접근 방식은 사용자가 포인터를 전달하도록하는 것입니다. 값을 채우지 않으려면 NULL 포인터를 전달합니다. 나는 null 객체 접근을 좋아합니다. 수신자 코드를 끔찍하게 복잡하게 만들지 않고 발신자 생활을 더 쉽게 만듭니다.