Значение по умолчанию для параметра при передаче по ссылке в С++

Можно ли задать значение по умолчанию для параметра функции, когда мы передаем параметр по ссылке. в С++

Например, когда я пытаюсь объявить такую ​​функцию, как:

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

Когда я это делаю, он дает ошибку:

ошибка C2440: "аргумент по умолчанию": невозможно преобразовать из "const int" в "unsigned long &" Ссылка, не относящаяся к 'const', не может быть привязана к не-lvalue

Ответ 1

Вы можете сделать это для ссылки const, но не для неконстантной. Это связано с тем, что С++ не позволяет временному (значение по умолчанию в этом случае) привязываться к неконстантной ссылке.

Один из способов: использовать фактический экземпляр по умолчанию:

static int AVAL = 1;

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

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

но это очень ограниченное практическое применение.

Ответ 2

Это уже было сказано в одном из прямых комментариев к вашему ответу, но просто официально заявить об этом. То, что вы хотите использовать, это перегрузка:

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
}

Есть только одна ситуация, когда по умолчанию действительно нужно использовать, и это находится в конструкторе. Невозможно вызвать один конструктор из другого, и поэтому этот метод не работает в этом случае.

Ответ 3

По-прежнему существует старая опция C предоставления необязательных аргументов: указатель, который может быть NULL, если нет:

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

Ответ 4

Этот небольшой шаблон поможет вам:

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

Ответ 5

Есть две причины передать аргумент по ссылке: (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);

Конечно, я не совсем уверен, что вы пишете или где. Но этот другой вопрос в другое время.

Ответ 6

Вы не можете использовать постоянный литерал для параметра по умолчанию по той же причине, что вы не можете использовать его в качестве параметра для вызова функции. Опорные значения должны иметь адрес, значения констант ссылки не нужны (т.е. Они могут быть 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, если они не хотят, чтобы вы заполнили значение. Мне нравится нулевой подход к объекту. Это облегчает жизнь абонентам без особого усложнения кода вызываемого абонента.

Ответ 7

Нет, это невозможно.

Передача по ссылке означает, что функция может изменить значение параметра. Если параметр не предоставлен вызывающим абонентом и исходит из константы по умолчанию, какова функция, которую необходимо изменить?

Ответ 8

Я думаю, что нет, и причина в том, что значения по умолчанию оцениваются в константах, а значения, переданные по ссылке, должны иметь возможность изменять, если вы также не объявляете ее постоянной ссылкой.

Ответ 9

Другим способом может быть следующее:

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

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

тогда возможны следующие вызовы:

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"

Ответ 10

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

Ответ 11

В случае OO... Сказать, что данный класс имеет и "Default" означает, что это значение по умолчанию (значение) должно быть объявлено отдельно, может быть usd в качестве параметра по умолчанию ex:

class Pagination {
public:
    int currentPage;
    //...
    Pagination() {
        currentPage = 1;
        //...
    }
    // your Default Pagination
    static Pagination& Default() {
        static Pagination pag;
        return pag;
    }
};

В вашем методе...

 shared_ptr<vector<Auditoria> > 
 findByFilter(Auditoria& audit, Pagination& pagination = Pagination::Default() ) {

Эти решения вполне подходят, так как в этом случае "Глобальная разбивка по умолчанию" является единственным значением "ссылки". У вас также будет возможность изменять значения по умолчанию во время выполнения, такие как конфигурация "gobal-level", например: пользовательские настройки навигации по страницам и т.д.

Ответ 12

Это возможно с помощью команды const для состояния:

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

Ответ 13

void revealSelection(const ScrollAlignment& = ScrollAlignment::alignCenterIfNeeded, bool revealExtent = false);

Ответ 14

Для этого существует довольно грязный трюк:

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

В этом случае вы должны называть его std::move:

ULONG val = 0;
Write(std::move(val));

Это всего лишь смешное обходное решение, я полностью не рекомендую его использовать в реальном коде!

Ответ 15

У меня есть обходное решение для этого, см. Следующий пример по умолчанию для int&:

class Helper
{
public:
    int x;
    operator int&() { return x; }
};

// How to use it:
void foo(int &x = Helper())
{

}

Вы можете сделать это для любого тривиального типа данных, который вы хотите, например, bool, double...

Ответ 16

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

Ответ довольно прост, и я не очень хорошо объясняю, но если вы хотите передать значение по умолчанию неконстантическому параметру, который, вероятно, будет изменен в этой функции, это использовать его следующим образом:

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