1

I have a class declaration I will use many times with different values for Titles and Values

class Generator
{
    public:
        String  Titles[9];     
        int16_t Values[9];
        byte    MainSel;
        void    SetTitles(String names[9])
                {
                    for (i = 0; i < 9; i++)
                        Titles[i] = names[i];
                }                   
        void    Update_Display()
                {
                    Display(__func__, Titles, Values, MainSel);
                }
};

I declare an instance of it and try to set the Titles using SetTitles

    Generator Organ_Levels;

    Organ_Levels.SetTitles("", "Rot", "Tone", "Sprd", "Bal", "Upper", "Lower", "Pedal", "Volume");

But the compiler seems to think I am passing char arrays :

No matching function for call to 'Generator::SetTitles(const char [1], const char [4], const char [5], const char [5], const char [4], const char [6], const char [6], const char [6], const char [7])'

Why doesn't it take them as instances of the Arduino String type?

2
  • 2
    What is String?Tthat's not the c++ standard implementation. Commented Mar 16, 2019 at 11:40
  • "But the compiler seems to think I am passing char arrays" You are. That's what string literals are. Commented Mar 18, 2019 at 2:05

3 Answers 3

4

It is not clear what String is, but I'll assume that it'll be similar to std::string.

Passing arrays as argument is a terrible idea. Go for a vector instead:

    void    SetTitles(vector<string> names)

You then can easily call it creating a vector on the flow, with just two braces more:

Organ_Levels.SetTitles({"", "Rot", "Tone", "Sprd", "Bal", "Upper", "Lower", "Pedal", "Volume"});    return 0;

Online demo

One step further would be to get rig of the array in your class as well. You can then replace your for loop to copy values one by one to simple assignment statement at vector level.

Sign up to request clarification or add additional context in comments.

Comments

4

Your SetTitles function expects an array of strings but in this line :

  Organ_Levels.SetTitles("", "Rot", "Tone", "Sprd", "Bal", "Upper", "Lower", "Pedal", "Volume");

you are calling a function with 9 parameters. define an array fill it with your data then pass it to SetTitles :

string names[9]={"", "Rot", "Tone", "Sprd", "Bal", "Upper", "Lower", "Pedal", "Volume"};
    Organ_Levels.SetTitles(names);

and I should mention that String is not a c++ type.

2 Comments

Yes that works but the code needs to be modified by musicians (hence some of the names) who aren't going to be expert programmers. Hence the need for simplicity with the names being directly in the function call.
Then you need to use vectors so that you can use initializer list in function call.
2

If you're using C++11 or above, you could call SetTitles as a variadic function (one that can be passed a variable number of arguments) by using parameter packs.

template<class ...Ts>
void SetTitles(Ts... args)    // accepts an arbitrary number of arguments
{
    std::vector<String> names {args...};   // unpacks the arguments into an initialiser list          
                                           // and constructs a vector with it

    const int size = std::min(9, names.size());     // size should be no bigger than 9      
                                                    //  to prevent undefined behaviour      
    // loop through the vector as normal
    for (int i = 0; i < size; i++)
        Titles[i] = names[i];
}

This then allows:

Organ_Levels.SetTitles("", "Rot", "Tone", "Sprd", "Bal", "Upper", "Lower", "Pedal", "Volume");

and even more:

Organ_Levels.SetTitles("p", "a", "r", "a", "m", "e", "t", "e", "r", " ", "p", "a", "c", "k", " ", "a", "b", "u", "s", "e");

However, since Generator::Titles has a size set to 9, the latter example is will only set at most 9 titles. To make this number dynamic, consider changing the String Titles[] array to an std::vector (e.g. std::vector<String> Titles). Note that you may need to change other parts of the code as well (e.g. int16_t Values[] array). There's also the added benefit that you can eliminate the loop by directly copying the vector:

template<class ...Ts>
void SetTitles(Ts... args)
{
    std::vector<String> names {args...};

    //  works if Titles is an std::vector
    Titles = names;
    //  Titles = std::vector<String>{args...}; // should also work
}

Thanks to Christophe's prompt.

2 Comments

This is a nice answer. Nevertheless, with the remaining code unchanged, the second example would be UB : names.size() would exceed the size of array Titles. If Titles is changed to a vector, the assignment loop could be replaced by a single vector assignment.
@Christophe Hope that's patched now. Thanks for the nudge.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.