Передача параметра по ссылке с++

301
28 января 2017, 10:21

Как передать функции параметр по ссылке со значением по умолчанию?

void func(int &i)
void func2(set<int> &s)

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

Answer 1

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

Передача аргумента по неконстантной ссылке предполагает, что этот исходный аргумент будет в функции изменен. Вы не можете передавать по неконстантной ссылке временные объекты.

Поэтому, исходя из условий, указанных в вашем вопросе, скорей всего у вас должны быть две перегруженные функции. Одна функция принимает аргумент по lvalue-ссылке с конкретно заданным объектом. Вторая функция оибл принимает временный объект по rvalue-сслке, оибо вместо него использует значение по умолчанию.

Например,

#include <iostream>
void func( int &i )
{
    ++i;
    std::cout << "Inside func( int & ) i = " << i << std::endl;
}   
void func( int &&i = int() )
{
    ++i;
    std::cout << "Insde func( int && ) i = " << i << std::endl;
}   

int main() 
{
    int i = 0;
    std::cout << "Before func( i ) i = " << i << std::endl;
    func( i );
    std::cout << "After  func( i ) i = " << i << std::endl;
    std::cout << std::endl;
    i = 0;
    std::cout << "Before func() i = " << i << std::endl;
    func();
    std::cout << "After  func() i = " << i << std::endl;
    return 0;
}

Вывод программы на консоль:

Before func( i ) i = 0
Inside func( int & ) i = 1
After  func( i ) i = 1
Before func() i = 0
Insde func( int && ) i = 1
After  func() i = 0

В этой программе, когда в качестве аргумента передается lvalue, то используется первая функция

void func( int &i )
{
    ++i;
    std::cout << "Inside func( int & ) i = " << i << std::endl;
}   

и она меняет в своем теле исходный аргумент.

Когда же аргумент не указывается, или когда указывается rvalue, то есть некоторый временный объект, как, например,

func(); // используется аргумент по умолчанию int(), который равен 0

или

func( 10 ); // используется временный объект - целочисленный литерал - 10

то используется вторая функция

void func( int &&i = int() )
{
    ++i;
    std::cout << "Insde func( int && ) i = " << i << std::endl;
}   

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

void func( const int &i = int() );
Answer 2

Ну, первый случай несложен - если вы хотите иметь возможность использовать значение по умолчанию, то используйте const int& -

void f(const int& i = 5)
{
    cout << i << endl;
}

Без const, как вы понимаете, вам не удастся передать значение - ведь что тогда вы собираетесь менять, передавая число? :)

А вот так - можно:

int j = 5;
void f(int& i = j)
{
    cout << i << endl;
}
int main(int argc, const char * argv[])
{
    int q = 4;
    f();
    f(q);
}

Соответственно, то же и с set<int>& - как вы себе представляете

для s вызывался конструктор, чтобы использовать множество set в теле функции

Т.е. вы хотите создавать новый set<int>? Тогда где он должен быть создан? Как локальная переменная, как глобальная, как переменная в вызывающей функции?

Так что по умолчанию для ссылки надо указывать имеющийся объект. Другое просто не имеет никакого смысла. В конце концов, ссылка - это просто адрес, ждя которого гарантируется наличие корректного объекта.

"По-моему, так" (с) Пух

Answer 3

Если вам нужна именно неконстантная ссылка, то сделать в такой ситуации можно что-то вроде

void func2(set<int> &s = some_function())

где some_function это

set<int> &some_function()
{
  ...
}

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

Оптимальное решение может зависеть от конкретной специфики вашей задачи, но сама идея неявного создания (потенциально долгоживущих) объектов через параметр по-умолчанию - сомнительна.

READ ALSO
Зацикливание обработки исключений

Зацикливание обработки исключений

Столкнулся с очень необычной проблемойПричем что интересно, происходит она только в одном случае, когда происходит отладка юнит тестов (если...

286
Как подключить sfe movie

Как подключить sfe movie

Я пытаюсь подключить это http://sfemovieyalir

464
проверка на существование файла си

проверка на существование файла си

Как проверить на существование файла си?

367