Search code examples
c++referencearguments

How to pass variable number of references in container or similar structure as argument to function


I want to pass variable number of references to objects to a C++ function. Say, I have class ParameterBase and instances of classes derived from this base class. I want a function, which checks that all parameters are specified.

//Abstract base class
class ParameterBase
{
public:
  std::string name();
  bool specified();
};

class ParameterInt : public ParameterBase
{
  //whatever
};

class ParameterString : public ParameterBase
{
  //whatever
};

/// Check that all parameters in the list are specified and 
/// print the name of the first unspecified parameter.
bool all_specified(const magic_container<ParameterBase&>& parameters)
{
  for(const auto& par : parameters)
  {
    if (!par.specified())
    {
      std::cerr << "Parameter '" << par.name() << "' was not specified\n";
      return false;
    }
  }
  return true;
}

int main()
{
  ParameterInt n1, n2, n3;
  ParameterString s1, s2, s3;
  if (all_specified({n1, n2, s1, n3, s2, s3}))
  {
    std::cout << "Joy and happiness\n";
  } else
  {
    std::cout << "Disaster\n";
  }
  return 0;
}

I understand, I can work around this problem using container of pointers or reference wrappers to objects, but may be I use wrong approach altogether? All I want is to be able to

  • pass to function an argument like this: {n1, n2, s1, n3, s2, s3} of variable size, all elements have common ancestor;
  • elements are not copied, but passed by (constant) reference;
  • iterate accross elements inside the function;

What is the simplest and most elegant way of doing this?


Solution

  • I would go with reference_wrapper or pointer container.

    but as alternative, you might use varaidic template:

    template <typename... Ts>
    bool all_specified(const Ts& parameters)
    {
        return ([&](){
            if (!parameters.specified()) {
                std::cerr << "Parameter '" << parameters.name() << "' was not specified\n";
                return false;
            } else {
                return true;
            }
        }() && ...);
    }
    

    And call would be similar to:

    if (all_specified(n1, n2, s1, n3, s2, s3))