0

I'm attempting to port some old code over from C# to C++, and I need to know if there's an efficient/clean method to translate a C# constructor that takes an argument of a params object[] over to C++.

In my example, I have the following simple constructor:

    public ParameterDescriptor(bool required, ParameterType parameterType, params object[] values)
    {
        this.optional = optional;
        this.parameterType = parameterType;
        this.defaultValues.AddRange(values);
    }

Where the values being inputted into the third argument can range from being absolutely blank to any number of command strings, i.e. "ON", "OFF", "RESET". These command strings then get added to a List containing each object value, through the following:

    List<object> defaultValues = new List<object>();
    public List<object> DefaultValues
    {
        get { return this.defaultValues; }
        set { this.defaultValues = value; }
    }

Is there any method in C++ that would achieve the same result here? That is to say, accept any number of string arguments from None to a large amount in the constructor and store them in a list/vector?

I feel as though multiple constructors for varying lengths of command strings would work, but that doesn't solve the possibility of an unknown X amount of strings being inputted. I feel as though va_args might be up the right alley, but they seem like a really messy solution. What would work best here?

Fields
  • 687
  • 1
  • 6
  • 13

1 Answers1

3

std::vector is precisely what you are looking for. Since C++11, it can be initialised much more easily anyway:

std::vector<int> v = { 1, 2, 3 };

However, the more difficult issue is how to best translate a C# object. C++ does not have any kind of root class. There is no such thing as object.

Sometimes, a good C++ alternative is to use a template instead. Here is an example, in which I've also used a correct C++ initialisation list, rather than assignments, and const correctness:

template <class T>
class ParameterDescriptor
{
    bool required;
    ParameterType parameterType;
    std::vector<T> defaultValues;

    // ...

    ParameterDescriptor(bool required, ParameterType const& parameterType, std::vector<T> const& values) :
        required(required),
        parameterType(paremeterType),
        defaultValues(values)
    { 
    }

    void setDefaultValues(std::vector<T> const& values)
    {
        defaultValues = values;
    }

    std::vector<T> getDefaultValues() const
    {
        return defaultValues;
    }
};

But it really depends on why you use object in C# in the first place. The point is, std::vector is the right choice here anyway, regardless of whether or not you use a template.

Chances are you are looking for something like boost::any. You could then use a std::vector<boost::any>.

I feel as though va_args might be up the right alley, but they seem like a really messy solution.

va_args would be a horrible solution. Don't even think about using it. Also stay away from raw arrays. Their syntactical similarity, being declared with the [] notation, might fool you into believing that they match the C# code more closely, but they don't.

Christian Hackl
  • 27,051
  • 3
  • 32
  • 62
  • 2
    I was just about to scratch something like this down when I saw this answer pop up :) Just wanted to note that if you really want an initializer list, you can also use a variadic template or `std::initializer_list`. The example from http://en.cppreference.com/w/cpp/utility/initializer_list tells the story, which is pretty much what he wants I suppose. – atlaste Mar 24 '16 at 20:39