2

I have a function that takes two parameters. The first parameter is an int& which the function will set to some "return" value. The second parameter is a pointer and is optional. The caller can pass a valid pointer if the caller wishes it to be initialized, and if not the default value is nullptr.

void find_lis(uint32_t& count,
              vector<uint32_t>* output = nullptr)
{ }

All is well. However, I want to make the second parameter a reference, and allow caller the same option to provide one or not, what should I use as the default value?

void find_lis(uint32_t& count,
              vector<uint32_t>& output = ???)
{ }

I tried a few things, but they cause a compiler error. However, the following at least compiles, but I am not sure if it is right?

void find_lis(uint32_t& count,
              vector<uint32_t>& output = *(new vector<uint32_t>()))
{ }

In the pointer case, I can easily check if the caller passed in a second parameter by comparing value to nullptr. However, in the reference case, I don't see any such easy check.

LThode
  • 1,843
  • 1
  • 17
  • 28
Ahmed A
  • 3,362
  • 7
  • 39
  • 57
  • In short there's really no good way to have a default argument for a reference. The way you solve it causes a memory leak every time you call the function without providing a value for that argument. – Some programmer dude Aug 05 '15 at 06:08
  • 1
    You have programmed a memory leak. Try this: `vector output = some_static_variable`. – n. m. could be an AI Aug 05 '15 at 06:09
  • "I an easily check if the caller passed in a second parameter by comparing value to nullptr" -- No, you cannot. There is nothing distinguishing a caller that omits the second argument and a caller that passes in `nullptr` explicitly. It may seem like a technicality, but try to understand this and you'll have an easier time thinking about your reference version. –  Aug 05 '15 at 06:17
  • Actually, let me rephrase my statement. "I can easily tell if the caller wants the the function to initialize the output parameter (whether the caller did not provide a second argument or provided a nullptr as the second second argument) by comparing output against nullptr". That is what I meant. – Ahmed A Aug 06 '15 at 00:51
  • possible duplicate of [Mixing pointers and references in function definition in C++](http://stackoverflow.com/questions/31807775/mixing-pointers-and-references-in-function-definition-in-c) – Quentin Aug 06 '15 at 15:04

2 Answers2

4

If the implementation of the function is not overly complex, I would suggest creating two overloaded functions.

void find_lis(uint32_t& count)
{
   count = 0; // ???
}

void find_lis(uint32_t& count,
              vector<uint32_t>& output)
{
   // Proper implementation
}

Another option:

void find_lis(uint32_t& count)
{
   // I'm guessing this will work. May be not.
   static vector<uint32_t> dummy;
   find_lis(count, dummy);
}

void find_lis(uint32_t& count,
              vector<uint32_t>& output)
{
   // Proper implementation
}

Update, in response to comment by OP

Use:

void find_lis_private(uint32_t& count,
                      vector<uint32_t>& output,
                      bool update)
{
   // Proper implementation
}

void find_lis(uint32_t& count)
{
   static vector<uint32_t> dummy;
   find_lis_private(count, dummy, false);
}

void find_lis(uint32_t& count,
              vector<uint32_t>& output)
{
   find_lis_private(count, output, true);
}

A better option is to use:

template <typename UpdateFunction>
void find_lis_private(uint32_t& count,
                      vector<uint32_t>& output,
                      UpdateFunction fun)
{
   // Proper implementation
   // call fun() with the necessary arguments when it's time
   // to update.
}

void find_lis(uint32_t& count)
{
   static vector<uint32_t> dummy;
   find_lis_private(count, dummy, [](args...) {/* Empty function */});
}

void find_lis(uint32_t& count,
              vector<uint32_t>& output)
{
   find_lis_private(count, output, [=output](args...) {/* Update output */});
}

Then, you don't have to use if/else blocks to update.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • Third option: both overload call the overload with pointer (which may be non public). – Jarod42 Aug 05 '15 at 09:50
  • For the first option, I don't think it will work. find_lis() with one parameter needs to call the other find_lis(), which I am not seeing in the code you provided. As for the second option, in find_lis() taking two parameters, how would one check if the output parameter is something the caller provided and needs to filled, or a dummy that find_lis can avoid initializing (aka less work to do). – Ahmed A Aug 06 '15 at 00:56
  • This might work, but slight correction to your code. In find_lis() that takes two parameters, you need to call find_lis() with three parameter withe the third argument as "true". (Or the other find_lis() that takes one argument needs to call with "true"). Both calls to the private function should not be called with same third argument value. – Ahmed A Aug 06 '15 at 01:21
  • @Jarod42, That's another possibility. I think a better option is to use `lambda` appropriately. – R Sahu Aug 06 '15 at 14:53
  • In the lambda case, I think we can even get ride of vector reference parameter. – Jarod42 Aug 06 '15 at 16:26
  • @Jarod42, Since the OP didn't provide the details of the function implementation, it's hard telling what's the best way to implement the *update* part of the function. – R Sahu Aug 06 '15 at 16:53
2

If you really want to bind a temporary to an lvalue reference, you can use a helper function to convert the rvalue to an lvalue:

template <class T>
T& lvalue_cast(T&& t)
{
    return t;
}

void find_lis(uint32_t& count,
              std::vector<uint32_t>& output = lvalue_cast(std::vector<uint32_t>()))
{
}
Paul Groke
  • 6,259
  • 2
  • 31
  • 32