Ответ 1
Аргумент по умолчанию (изменяемой) ссылки должен быть l-значением. Самое лучшее, о чем я могу думать, без перегрузки, -
static double _dummy_foobar;
void foo(double &bar, double &foobar = _dummy_foobar)
У меня возникла проблема с необязательным параметром функции в С++
То, что я пытаюсь сделать, это написать функцию с необязательным параметром, который передается по ссылке, так что я могу использовать его двумя способами (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'
Можно ли решить эту проблему без перегрузки функции?
Аргумент по умолчанию (изменяемой) ссылки должен быть l-значением. Самое лучшее, о чем я могу думать, без перегрузки, -
static double _dummy_foobar;
void foo(double &bar, double &foobar = _dummy_foobar)
Не используйте ссылки для дополнительных параметров. Нет понятия ссылки NULL: ссылка всегда является псевдонимом для определенного объекта.
Возможно, посмотрите boost::optional
или std::experimental::optional
. boost::optional
даже специализирован для ссылочных типов!
void foo(double &bar, optional<double &> foobar = optional<double &>())
Почему вы не можете использовать перегрузку функций? Наверняка это самое простое решение вашей проблемы?
void foo(double &bar, double &foobar)
{
bar = 100;
foobar = 150;
}
void foo(double &bar)
{
double foobar = 0.0;
foo(bar, foobar);
}
Другой способ сделать это - использовать указатели вместо ссылок. Это обеспечивает семантику, которую вы хотите без перегрузки. (Лично я, вероятно, перейду с перегрузкой.)
void foo(double* bar, double* foobar = 0)
{
if (bar) *bar = 100;
if (foobar) *foobar = 150;
}
// ...
foo(&mBar, &mFoobar);
// ...
foo(&mBar);
// ...
Вот еще один безумный способ, который не приводит к утечкам памяти, которые вы никогда не должны использовать в реальной жизни, но с первого взгляда кажется стандартным, совместимым с 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;
}
Повторить: НЕ ДЕЛАЙТЕ ЭТО! ЛУЧШИЕ ВАРИАНТЫ! ПЕРЕГРУЗКА МОЖЕТ БЫТЬ ВАШИМ ДРУГОМ! Но да, вы можете это сделать, если вы глупы и осторожны.:)
Гораздо проще использовать тип указателя и установить его в NULL, чем устанавливать значение по умолчанию/необязательное значение для ссылочного параметра.
Говоря в терминах объектно-ориентированной парадигмы: если заданный класс имеет и "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: правописание и исправление...
Вот как я решил этот вопрос:
У моей исходной функции не было возвращенной строки ошибки: 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, не проверяя, действительно ли он, и нет утечек памяти.
Вы можете сделать это безумным способом:
void foo(double &bar, double &foobar = (*(new double())))
P.S. - Я знаю, что это не приятно, но это путь. Также не оставляйте утечки памяти!:))