Home > Net >  What mechanism can I use for an optional function parameter that gets a value assigned if not provid
What mechanism can I use for an optional function parameter that gets a value assigned if not provid

Time:12-03

In Python I can do something like:

def add_postfix(name: str, postfix: str = None):
  if base is None:
    postfix = some_computation_based_on_name(name)
  return name   postfix

So I have an optional parameter which, if not provided, gets assigned a value. Notice that I don't have a constant default for postfix. It needs to be calculated. (which is why I can't just have a default value).

In C I reached for std::optional and tried:

std::string add_postfix(const std::string& name, std::optional<const std::string&> postfix) {
  if (!postfix.has_value()) { postfix.emplace("2") };
  return name   postfix;
}

I'm now aware that this won't work because std::optional<T&> is not a thing in C . I'm fine with that.

But now what mechanism should I use to achieve the following:

  • Maintain the benefits of const T&: no copy and don't modify the original.
  • Don't have to make some other postfix_ so that I have the optional one and the final one.
  • Don't have to overload.
  • Have multiple of these optional parameters in one function signature.

CodePudding user response:

You do this with two functions:

std::string add_postfix(const std::string& name, const std::string& postfix) {
// whatever
}

std::string add_default_postfix(const std::string& name) {
return add_postfix(name, "2");
}

Or, if you're into overloading, you can write the second one as an overload by naming it add_postfix.

CodePudding user response:

One possibility is to use a std::string const* (a non-constant pointer to a const std::string) as a function argument.

std::string add_postfix(const std::string& name, std::string const* postfix = nullptr) 
{
  std::string derivedSuffix;
  if(!postfix) 
  { 
    derivedSuffix = some_computation(name); 
    postfix = &derivedSuffix;
  }
  return name   *postfix;
}

Some care is required with the details here. derivedSuffix needs to be an object that lasts at least as long as the pointer postfix refers to it. Therefore it cannot be contained entirely within the if(!postfix) block, because if it did then using *postfix outside of it would be invalid. There's technically still a bit of overhead here where we create an empty std::string even when postfix isn't nullptr, but we never have to make a copy of a std::string with actual values in it.

CodePudding user response:

You simply can write:

std::string add_postfix(const std::string& name, const std::string& postfix = "default value")
{
   return name   postfix;
}

CodePudding user response:

With your usage, value_or seems to do the job:

std::string add_postfix(const std::string& name,
                        const std::optional<std::string>& postfix)
{
    return name   postfix.value_or("2");
}

If you really want optional<T&>, optional<reference_wrapper<T>> might do the job.

std::string add_postfix(const std::string& name,
                        const std::optional<std::reference_wrapper<const std::string>>& postfix)
{
#if 1
    const std::string postfix_ = "2";
    return name   postfix.value_or(postfix_).get();
#else    // or
    return name   (postfix.has_value() ? postfix->get() : "2");
#endif
}

Demo

  •  Tags:  
  • c
  • Related