Подтвердить что ты не робот

Передача необязательного параметра по ссылке в С++

У меня возникла проблема с необязательным параметром функции в С++

То, что я пытаюсь сделать, это написать функцию с необязательным параметром, который передается по ссылке, так что я могу использовать его двумя способами (1) и (2), но на (2) я действительно не обратите внимание на то, что значение mFoobar.

Я пробовал такой код:

void foo(double &bar, double &foobar = NULL)
{
   bar = 100;
   foobar = 150;
}

int main()
{
  double mBar(0),mFoobar(0);

  foo(mBar,mFoobar);              // (1)
  cout << mBar << mFoobar;

  mBar = 0;
  mFoobar = 0;

  foo(mBar);                     // (2)
  cout << mBar << mFoobar;

  return 0;
}

но он падает при

void foo(double &bar, double &foobar = NULL)

с сообщением:

error: default argument for 'double& foobar' has type 'int'

Можно ли решить эту проблему без перегрузки функции?

4b9b3361

Ответ 1

Аргумент по умолчанию (изменяемой) ссылки должен быть l-значением. Самое лучшее, о чем я могу думать, без перегрузки, -

static double _dummy_foobar;
void foo(double &bar, double &foobar = _dummy_foobar)

Ответ 2

Не используйте ссылки для дополнительных параметров. Нет понятия ссылки NULL: ссылка всегда является псевдонимом для определенного объекта.

Возможно, посмотрите boost::optional или std::experimental::optional. boost::optional даже специализирован для ссылочных типов!

void foo(double &bar, optional<double &> foobar = optional<double &>())

Ответ 3

Почему вы не можете использовать перегрузку функций? Наверняка это самое простое решение вашей проблемы?

void foo(double &bar, double &foobar) 
{ 
   bar = 100; 
   foobar = 150; 
}

void foo(double &bar) 
{ 
   double foobar = 0.0;
   foo(bar, foobar);
}

Ответ 4

Другой способ сделать это - использовать указатели вместо ссылок. Это обеспечивает семантику, которую вы хотите без перегрузки. (Лично я, вероятно, перейду с перегрузкой.)

void foo(double* bar, double* foobar = 0)
{
   if (bar) *bar = 100;
   if (foobar) *foobar = 150;
}

   // ...

   foo(&mBar, &mFoobar);

   // ...

   foo(&mBar);

   // ...

Ответ 5

Вот еще один безумный способ, который не приводит к утечкам памяти, которые вы никогда не должны использовать в реальной жизни, но с первого взгляда кажется стандартным, совместимым с Visual С++ 2008 и g++ 3.4.4 под Cygwin:

void foo(double &bar, double &foobar = (*((double*)0)))
{
   bar = 100;
   double* pfoobar = &foobar;
   if (pfoobar != 0)
       foobar = 150;
}

Повторить: НЕ ДЕЛАЙТЕ ЭТО! ЛУЧШИЕ ВАРИАНТЫ! ПЕРЕГРУЗКА МОЖЕТ БЫТЬ ВАШИМ ДРУГОМ! Но да, вы можете это сделать, если вы глупы и осторожны.:)

Ответ 6

Гораздо проще использовать тип указателя и установить его в NULL, чем устанавливать значение по умолчанию/необязательное значение для ссылочного параметра.

Ответ 7

Говоря в терминах объектно-ориентированной парадигмы: если заданный класс имеет и "Default", это значение по умолчанию должно быть объявлено соответствующим образом, а затем может использоваться как "параметр по умолчанию", Пример:

class Pagination {
private:
    int currentPage;
public:

    //...
    Pagination() {
        currentPage = 1;
        //...
    }

    // your Default Pagination (Must be initialized before thread concurrency)
    static Pagination& Default() {
        static Pagination p; 
        return p;
    }
};

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

     //...
     std::vector<User>
     findByFilter(User& audit, Pagination& p = Pagination::Default() ) {
     // ...

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

Edit2: правописание и исправление...

Ответ 8

Вот как я решил этот вопрос:

У моей исходной функции не было возвращенной строки ошибки: bool MyClass :: validateXML (const QString & fileName, const QUri & schemaUri);

Я хотел добавить результаты проверки в строку ошибки, поэтому я реализовал: bool MyClass :: validateXML (const QString & fileName, const QUri & schemaUri, QString & errorString = * (std :: make_unique(). Get()));

Таким образом, вы можете ссылаться на errorString в validateXML, не проверяя, действительно ли он, и нет утечек памяти.

Ответ 9

Вы можете сделать это безумным способом:

void foo(double &bar, double &foobar = (*(new double())))

P.S. - Я знаю, что это не приятно, но это путь. Также не оставляйте утечки памяти!:))