Передача необязательного параметра по ссылке в c ++ - PullRequest
30 голосов
/ 12 мая 2010

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

То, что я пытаюсь сделать, это написать функцию с необязательным параметром, который передается по ссылке, чтобы я мог использовать его двумя способами (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'

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

Ответы [ 9 ]

38 голосов
/ 12 мая 2010

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

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

void foo(double &bar, optional<double &> foobar = optional<double &>())
31 голосов
/ 12 мая 2010

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

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

void foo(double &bar) 
{ 
   double foobar = 0.0;
   foo(bar, foobar);
}
28 голосов
/ 12 мая 2010

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

static double _dummy_foobar;
void foo(double &bar, double &foobar = _dummy_foobar)
5 голосов
/ 12 мая 2010

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

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

   // ...

   foo(&mBar, &mFoobar);

   // ...

   foo(&mBar);

   // ...
3 голосов
/ 23 марта 2011

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

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

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

1 голос
/ 01 июня 2012

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

0 голосов
/ 05 декабря 2018

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

В моей исходной функции не было возвращенной строки ошибки: 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, не проверяя, является ли он действительным, и нет утечек памяти.

0 голосов
/ 30 апреля 2014

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

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: правописание и исправление ...

0 голосов
/ 12 мая 2010

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

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

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

...