Когда функции принимают неконстантные ссылки в качестве аргументов, они могут создать трудно читаемый код, потому что на вызывающем сайте не очевидно, какие входные данные могут быть изменены. Это привело к тому, что некоторые условные обозначения в коде заставляют использовать указатели, например
void func(int input, int* output);
int input = 1, output = 0;
func(input, &output);
вместо
void func(int input, int& output);
int input = 1, output = 0;
func(input, output);
Лично я ненавижу использовать указатели из-за необходимости проверять нулевое значение. Это заставило меня задуматься о том, может ли boost :: ref (или std :: ref для C ++ 11) использоваться для обозначения намерения следующим образом:
void func(int input, int& output);
int input = 1, output = 0;
func(input, boost::ref(output));
Это будет использоваться в качестве соглашения о кодировании компании. Мой вопрос: есть ли причины, по которым это не будет хорошей идеей?
Это неплохая идея, но она на самом деле не соблюдается (как отмечает ПетрНыч). Это фактически просто комментарий.
Мы можем сделать лучше, хотя:
template <typename T>
class output_argument
{
public:
template <typename U>
friend output_argument<U> out(U& ref);
T& get() const
{
return mRef;
}
operator T&() const
{
return get();
}
private:
explicit output_argument(T& ref) :
mRef(ref)
{}
output_argument& operator=(const output_argument&); // not defined
T& mRef;
};
template <typename U>
output_argument<U> out(U& ref)
{
return output_argument<U>(ref);
}
Предоставление:
void foo(int x, output_argument<float> f)
{
int i = static_cast<int>(f);
f.get() = static_cast<float>(i + x);
}
int main()
{
float f = 5.0f;
//fails: foo(1, f);
foo(1, out(f));
}
Но обычно такие утилиты не нужны, потому что имя функции должно передавать то, что происходит с аргументами: swap(x, y)
довольно четко изменяет аргументы! И возвращать значения следует с типом возврата, что еще больше ограничивает возможности использования этой утилиты.
Это соглашение о кодировании компании может быть легко (по ошибке, конечно) нарушено так:
void func(int input, int& output);
int input = 1, output = 0;
func(boost::ref(input), output);
это компилируется и работает нормально — но вводит в заблуждение читателей.
Лучше было бы назвать func добрым именем, предлагая изменить некоторые аргументы в нем:
void copyTo(int input, int& output);
В современной IDE — вы можете видеть, читая, что делает функция.
Может быть, лучше соглашение о кодировании компании будет наоборот, используя boost :: cref:
void func(int input, int& output);
int input = 1, output = 0;
func(boost::cref(input), output);
Здесь ошибки как с boost :: ref невозможны …